mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-09-13 10:49:56 +00:00
Compare commits
30 Commits
python-upd
...
r-updates
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35c83af8b8 | ||
|
|
7fa5f84179 | ||
|
|
91d8de0e1b | ||
|
|
befba536a5 | ||
|
|
84b2cfe60e | ||
|
|
8ade1f069e | ||
|
|
3921cb2f52 | ||
|
|
c4f343e091 | ||
|
|
f12c2fc819 | ||
|
|
180812aa8b | ||
|
|
99e50baea2 | ||
|
|
5e7cdb6263 | ||
|
|
375523bb1a | ||
|
|
3300252793 | ||
|
|
9e4efccb2b | ||
|
|
e15bd38348 | ||
|
|
d0d54e1ad4 | ||
|
|
16eadf108d | ||
|
|
1966470456 | ||
|
|
18a6b995b9 | ||
|
|
f2a6351124 | ||
|
|
cef26c7c61 | ||
|
|
fd8ab89e5d | ||
|
|
c76bc9e733 | ||
|
|
3f975f295a | ||
|
|
3ecb4f82d3 | ||
|
|
dd497f7abd | ||
|
|
21bc93c967 | ||
|
|
e34a43b2fa | ||
|
|
3f79d0dd24 |
20
.github/labeler.yml
vendored
20
.github/labeler.yml
vendored
@@ -43,6 +43,14 @@
|
||||
- .github/**/*
|
||||
- ci/**/*.*
|
||||
|
||||
"6.topic: coq":
|
||||
- any:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- pkgs/applications/science/logic/coq/**/*
|
||||
- pkgs/development/coq-modules/**/*
|
||||
- pkgs/top-level/coq-packages.nix
|
||||
|
||||
"6.topic: COSMIC":
|
||||
- any:
|
||||
- changed-files:
|
||||
@@ -458,18 +466,6 @@
|
||||
- any-glob-to-any-file:
|
||||
- pkgs/development/rocm-modules/**/*
|
||||
|
||||
"6.topic: rocq":
|
||||
- any:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- pkgs/applications/science/logic/coq/**/*
|
||||
- pkgs/applications/science/logic/rocq-core/**/*
|
||||
- pkgs/build-support/coq/**/*
|
||||
- pkgs/build-support/rocq/**/*
|
||||
- pkgs/development/rocq-modules/**/*
|
||||
- pkgs/top-level/coq-packages.nix
|
||||
- pkgs/top-level/rocq-packages.nix
|
||||
|
||||
"6.topic: ruby":
|
||||
- any:
|
||||
- changed-files:
|
||||
|
||||
@@ -466,8 +466,9 @@ nixos/tests/incus/ @adamcstephens
|
||||
pkgs/by-name/in/incus/ @adamcstephens
|
||||
pkgs/by-name/lx/lxc* @adamcstephens
|
||||
|
||||
# Flutter
|
||||
# ExpidusOS, Flutter
|
||||
/pkgs/development/compilers/flutter @RossComputerGuy
|
||||
/pkgs/desktops/expidus @RossComputerGuy
|
||||
|
||||
# GNU Tar & Zip
|
||||
/pkgs/by-name/gn/gnutar @RossComputerGuy
|
||||
|
||||
@@ -68,7 +68,7 @@ See [](#ex-portableService-hello) to understand how to use the output of `portab
|
||||
|
||||
: Allows you to override the package that provides {manpage}`mksquashfs(1)`, which is used internally by `portableService`.
|
||||
|
||||
_Default value:_ `pkgs.squashfs-tools`.
|
||||
_Default value:_ `pkgs.squashfsTools`.
|
||||
|
||||
`squash-compression` (String; _optional_)
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ Here is how your `default.nix` file would look for a Phoenix project.
|
||||
# beam27Packages or beam29Packages is available if you need a particular version
|
||||
beamPackages,
|
||||
}:
|
||||
beamPackages.mixRelease (finalAttrs: {
|
||||
let
|
||||
pname = "your_project";
|
||||
version = "0.0.1";
|
||||
|
||||
@@ -215,6 +215,24 @@ beamPackages.mixRelease (finalAttrs: {
|
||||
rev = "replace_with_your_commit";
|
||||
};
|
||||
|
||||
# if using mix2nix you can use the mixNixDeps attribute
|
||||
mixFodDeps = beamPackages.fetchMixDeps {
|
||||
pname = "mix-deps-${pname}";
|
||||
inherit src version;
|
||||
# nix will complain and tell you the right value to replace this with
|
||||
hash = lib.fakeHash;
|
||||
mixEnv = ""; # default is "prod", when empty includes all dependencies, such as "dev", "test".
|
||||
# if you have build time environment variables add them here
|
||||
MY_ENV_VAR = "my_value";
|
||||
};
|
||||
in
|
||||
beamPackages.mixRelease {
|
||||
inherit
|
||||
src
|
||||
pname
|
||||
version
|
||||
mixFodDeps
|
||||
;
|
||||
# if you have build time environment variables add them here
|
||||
MY_ENV_VAR = "my_value";
|
||||
|
||||
@@ -224,18 +242,7 @@ beamPackages.mixRelease (finalAttrs: {
|
||||
mix do deps.loadpaths --no-deps-check, phx.digest
|
||||
mix phx.digest --no-deps-check
|
||||
'';
|
||||
|
||||
# if using mix2nix you can use the mixNixDeps attribute
|
||||
mixFodDeps = beamPackages.fetchMixDeps {
|
||||
pname = "mix-deps-${finalAttrs.pname}";
|
||||
inherit (finalAttrs) src version;
|
||||
# nix will complain and tell you the right value to replace this with
|
||||
hash = lib.fakeHash;
|
||||
mixEnv = ""; # default is "prod", when empty includes all dependencies, such as "dev", "test".
|
||||
# if you have build time environment variables add them here
|
||||
MY_ENV_VAR = "my_value";
|
||||
};
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Setup will require the following steps:
|
||||
|
||||
@@ -59,9 +59,6 @@ Here is a simple package example.
|
||||
- The library will be installed using the `angstrom.install` file that dune
|
||||
generates.
|
||||
|
||||
- It also accepts an optional `dunePackages` argument, if there is more than one
|
||||
dune package that needs to be built (see `zipperposition`)
|
||||
|
||||
```nix
|
||||
{
|
||||
lib,
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
Note that "The Rocq Prover" (Rocq for short) is the new name of the
|
||||
proof assistant formerly known as Coq. The `coq` and `coqPackages`
|
||||
derivations currently remain for both older versions of Coq, but also
|
||||
as compatibility aliases for some versions of Rocq. In both cases, the
|
||||
`coq` and `rocq-core` attributes exist. In the case of Coq (< 9),
|
||||
`rocq-core` is just an alias for `coq`, while in the case of Rocq (>= 9),
|
||||
`rocq-core` is the main Rocq derivation, while `coq` provides
|
||||
compatibility binaries (`coqc`, `coqtop`, etc.) for packages that still
|
||||
depend on them.
|
||||
some versions of Rocq during the renaming transition. In the latter
|
||||
case, the `coq` derivation encompasses the compatibility binaries
|
||||
(`coqtop`, `coqc`, etc.) in addition to the `rocq` binary. The packages
|
||||
only in `coqPackages` are the ones which currently still depend on these
|
||||
compatibility binaries.
|
||||
|
||||
## Rocq derivation: `rocq-core` {#rocq-derivation-rocq}
|
||||
|
||||
@@ -18,18 +17,18 @@ The Rocq derivation is overridable through the `rocq-core.override overrides`, w
|
||||
* `customOCamlPackages` (optional, defaults to `null`, which lets Rocq choose a version automatically), which can be set to any of the ocaml packages attribute of `ocaml-ng` (such as `ocaml-ng.ocamlPackages_4_14` which is the default for Rocq 9.1 for example).
|
||||
* `rocq-version` (optional, defaults to the short version e.g. "9.1"), is a version number of the form "x.y" that indicates which Rocq's version build behavior to mimic when using a source which is not a release. E.g. `rocq-core.override { version = "40be8435e132aab2231a79091f011ebc3e64a753"; rocq-version = "9.1"; }`.
|
||||
|
||||
## Creating custom Coq environments with `rocq-core.withPackages` {#coq-withPackages}
|
||||
## Creating custom Coq environments with `coq.withPackages` {#coq-withPackages}
|
||||
|
||||
The `rocq-core.withPackages` function provides a convenient way to create a Rocq environment that includes additional Rocq packages. This is similar to how `python.withPackages` works for Python environments.
|
||||
The `coq.withPackages` function provides a convenient way to create a Coq environment that includes additional Coq packages. This is similar to how `python.withPackages` works for Python environments.
|
||||
|
||||
The function takes a function that receives the Rocq package set and returns a list of packages. It returns a wrapped Rocq environment where the Rocq binaries (`rocq`, etc.) are configured with the appropriate environment variables to find the packages.
|
||||
The function takes a function that receives the Coq package set and returns a list of packages. It returns a wrapped Coq environment where all Coq binaries (`coqtop`, `coqc`, `coqdep`, `coqchk`, `coqide`, etc.) are configured with the appropriate environment variables to find the packages.
|
||||
|
||||
### Usage {#coq-withPackages-usage}
|
||||
|
||||
Here is an example of creating a Rocq environment with specific packages.
|
||||
Here is an example of creating a Coq environment with specific packages.
|
||||
|
||||
```nix
|
||||
rocq-core.withPackages (
|
||||
coq.withPackages (
|
||||
ps: with ps; [
|
||||
mathcomp
|
||||
bignums
|
||||
@@ -37,9 +36,7 @@ rocq-core.withPackages (
|
||||
)
|
||||
```
|
||||
|
||||
If you install the `vsrocq-language-server` or `rocq-lsp` server, make sure to list them as part of the above `rocq-core.withPackages` expression instead of installing them separately if you want them to find your Rocq packages.
|
||||
|
||||
For versions prior to Rocq 9.0, a similar `coq.withPackages` function is available.
|
||||
If you install the `vsrocq-language-server` or `rocq-lsp` server, make sure to list them as part of the above `coq.withPackages` expression instead of installing them separately if you want them to find your Coq/Rocq packages.
|
||||
|
||||
## Rocq packages attribute sets: `rocqPackages` {#rocq-packages-attribute-sets-rocqpackages}
|
||||
|
||||
@@ -133,7 +130,7 @@ mkRocqDerivation {
|
||||
mathcomp.boot
|
||||
mathcomp.algebra
|
||||
mathcomp-finmap
|
||||
mathcomp.finite-group
|
||||
mathcomp.fingroup
|
||||
mathcomp-bigenough
|
||||
];
|
||||
|
||||
|
||||
@@ -82,8 +82,6 @@
|
||||
|
||||
- `nix-serve-ng` (and `haskellPackages.nix-serve-ng`) is now built against Lix instead of CppNix, following upstream which has switched to Lix as its supported Nix implementation.
|
||||
|
||||
- `buildPythonPackage` and `buildPythonApplication` now set `__structuredAttrs = true` by default. You can explicitly set `__structuredAttrs = false` in packages broken by this change.
|
||||
|
||||
- Linux kernel configuration has been moved out of the `linux-kernel` field of the platform structure into the kernel builders:
|
||||
- `linux-kernel.name` has been removed.
|
||||
- `linux-kernel.target` is available as the `target` parameter and passthru attribute on the kernel builders.
|
||||
@@ -119,8 +117,6 @@
|
||||
|
||||
- `gh-actions-cache` has been removed since its functionality has been integrated directly into `gh` (`gh cache`). See [upstream readme](https://github.com/actions/gh-actions-cache).
|
||||
|
||||
- The OCaml-based Xen Store Daemon has been split off the `xen` package, and is now present in the `ocamlPackages.oxenstored` package.
|
||||
|
||||
- `requireFile` now sets `meta.license = lib.licenses.unfree` by default. Users of `requireFile`-based derivations that preserve this default will need to explicitly allow their evaluation as described in [](#sec-allow-unfree).
|
||||
|
||||
- `texlive.combine` is deprecated and scheduled for removal in 27.05. Please migrate to `texliveSmall.withPackages` (see [](#sec-language-texlive-user-guide)).
|
||||
@@ -140,8 +136,6 @@
|
||||
[pnpm `fetcherVersion` section](#javascript-pnpm-fetcherVersion) of the manual
|
||||
for details.
|
||||
|
||||
- `makeSetupHook` now uses structured attributes and only makes substitutions based on the values of the `substitutions` argument - other derivation attributes are no longer considered.
|
||||
|
||||
- `rebuilderd` has been updated to 0.27.0 introducing breaking changes. See upstream changelog for details: [0.26.0](https://github.com/kpcyrd/rebuilderd/releases/tag/v0.26.0), [0.27.0](https://github.com/kpcyrd/rebuilderd/releases/tag/v0.27.0)
|
||||
|
||||
- Starting with v14, `flameshot` will primarily utilise xdg-desktop-portal calls for screenshotting. This will directly affect users on X11 window managers due to the lack of a compatible portal with Screenshot feature. See [upstream changelog](https://github.com/flameshot-org/flameshot/releases/tag/v14.0.0) or [NixOS Flameshot](https://wiki.nixos.org/wiki/Flameshot) wiki page for workarounds.
|
||||
@@ -169,8 +163,6 @@
|
||||
|
||||
- The fwts efi-runtime kernel module was removed.
|
||||
|
||||
- `homebox` v0.26.0 introduced a new, required value to be set, `HBOX_AUTH_API_KEY_PEPPER`. If one is not provided the module will create one, it is recommended that you back this up as it is part of API Key generation and validation.
|
||||
|
||||
- Emacs loads the `early-default` library after `early-init.el`.
|
||||
Users can add `early-init.el` via `emacs.pkgs.withPackages`
|
||||
by packaging `early-init.el` into a library named `early-default`.
|
||||
|
||||
@@ -349,33 +349,24 @@ rec {
|
||||
```
|
||||
*/
|
||||
_normaliseTreeFilter =
|
||||
let
|
||||
# Recurses into a tree that's already known to be a directory (either a "directory" or an attrset).
|
||||
#
|
||||
# Only directories need to be recursed into:
|
||||
# Files are either null (excluded) or a file type string (included), which are already normalised.
|
||||
#
|
||||
# Checking this in the caller instead of here also avoids the thunk allocation for the path concatenation below.
|
||||
recurse =
|
||||
path: tree:
|
||||
let
|
||||
normalisedSubtrees = mapAttrs (
|
||||
name: subtree:
|
||||
if subtree == "directory" || isAttrs subtree then recurse (path + "/${name}") subtree else subtree
|
||||
) (_directoryEntries path tree);
|
||||
subtreeValues = attrValues normalisedSubtrees;
|
||||
in
|
||||
# This triggers either when all files in a directory are filtered out
|
||||
# Or when the directory doesn't contain any files at all
|
||||
if all isNull subtreeValues then
|
||||
null
|
||||
# Triggers when we have the same as a `readDir path`, so we can turn it back into an equivalent "directory".
|
||||
else if all isString subtreeValues then
|
||||
"directory"
|
||||
else
|
||||
normalisedSubtrees;
|
||||
in
|
||||
path: tree: if tree == "directory" || isAttrs tree then recurse path tree else tree;
|
||||
path: tree:
|
||||
if tree == "directory" || isAttrs tree then
|
||||
let
|
||||
entries = _directoryEntries path tree;
|
||||
normalisedSubtrees = mapAttrs (name: _normaliseTreeFilter (path + "/${name}")) entries;
|
||||
subtreeValues = attrValues normalisedSubtrees;
|
||||
in
|
||||
# This triggers either when all files in a directory are filtered out
|
||||
# Or when the directory doesn't contain any files at all
|
||||
if all isNull subtreeValues then
|
||||
null
|
||||
# Triggers when we have the same as a `readDir path`, so we can turn it back into an equivalent "directory".
|
||||
else if all isString subtreeValues then
|
||||
"directory"
|
||||
else
|
||||
normalisedSubtrees
|
||||
else
|
||||
tree;
|
||||
|
||||
/**
|
||||
A minimal normalisation of a filesetTree, intended for pretty-printing:
|
||||
@@ -535,9 +526,6 @@ rec {
|
||||
else
|
||||
"/" + concatStringsSep "/" fileset._internalBaseComponents + "/";
|
||||
|
||||
getBaseStringPrefix = substring 0 baseLength;
|
||||
removeBaseStringPrefix = substring baseLength (-1);
|
||||
|
||||
baseLength = stringLength baseString;
|
||||
|
||||
# Check whether a list of path components under the base path exists in the tree.
|
||||
@@ -563,12 +551,7 @@ rec {
|
||||
# or a string ("directory" or "regular", etc.) in which case it's included
|
||||
localTree != null;
|
||||
in
|
||||
# Start by recursing into the first element. This is guaranteed to be
|
||||
# safe. components will never be empty (builtins.split can't make an
|
||||
# empty list). Tree can be something other than an attrset, but if so,
|
||||
# the isAttrs check will fail when being passed `or tree`, and the index
|
||||
# being ahead doesn't matter.
|
||||
recurse 2 (tree.${head components} or tree);
|
||||
recurse 0 tree;
|
||||
|
||||
# Filter suited when there's no files
|
||||
empty = _: _: false;
|
||||
@@ -586,34 +569,25 @@ rec {
|
||||
pathSlash = path + "/";
|
||||
in
|
||||
(
|
||||
# Same as `hasPrefix baseString pathSlash`, but more efficient.
|
||||
# The path is either the base itself or underneath it,
|
||||
# but only on the few paths above it, so its checked first.
|
||||
# With base /foo/bar this matches /foo/bar and /foo/bar/baz
|
||||
# hasPrefix "/foo/bar/" "/foo/bar/baz/"
|
||||
if getBaseStringPrefix pathSlash == baseString then
|
||||
if pathSlash == baseString then
|
||||
# The path is the base directory itself, which is always included
|
||||
true
|
||||
else
|
||||
# Same as `removePrefix baseString path`, but more efficient.
|
||||
# From the above code we know that hasPrefix baseString pathSlash holds, so this is safe.
|
||||
# We don't use pathSlash here because we only needed the trailing slash for the prefix matching.
|
||||
# With base /foo and path /foo/bar/baz this gives
|
||||
# inTree (split "/" (removePrefix "/foo/" "/foo/bar/baz"))
|
||||
# == inTree (split "/" "bar/baz")
|
||||
# == inTree [ "bar" "baz" ]
|
||||
inTree (split "/" (removeBaseStringPrefix path))
|
||||
# Same as `hasPrefix pathSlash baseString`, but more efficient.
|
||||
# The path is a proper ancestor of the base, which needs to be included for the base to be reachable:
|
||||
# With base /foo/bar we need to include /foo:
|
||||
# hasPrefix "/foo/" "/foo/bar/"
|
||||
else if substring 0 (stringLength pathSlash) baseString == pathSlash then
|
||||
if substring 0 (stringLength pathSlash) baseString == pathSlash then
|
||||
true
|
||||
else
|
||||
# The path is unrelated to the base, so nothing from it is included
|
||||
# With base /foo/bar this matches e.g. /baz
|
||||
# Same as `! hasPrefix baseString pathSlash`, but more efficient.
|
||||
# With base /foo/bar we need to exclude /baz
|
||||
# ! hasPrefix "/baz/" "/foo/bar/"
|
||||
else if substring 0 baseLength pathSlash != baseString then
|
||||
false
|
||||
else
|
||||
# Same as `removePrefix baseString path`, but more efficient.
|
||||
# From the above code we know that hasPrefix baseString pathSlash holds, so this is safe.
|
||||
# We don't use pathSlash here because we only needed the trailing slash for the prefix matching.
|
||||
# With base /foo and path /foo/bar/baz this gives
|
||||
# inTree (split "/" (removePrefix "/foo/" "/foo/bar/baz"))
|
||||
# == inTree (split "/" "bar/baz")
|
||||
# == inTree [ "bar" "baz" ]
|
||||
inTree (split "/" (substring baseLength (-1) path))
|
||||
)
|
||||
# This is a way have an additional check in case the above is true without any significant performance cost
|
||||
&& (
|
||||
@@ -828,34 +802,21 @@ rec {
|
||||
*/
|
||||
_unionTrees =
|
||||
trees:
|
||||
if length trees == 1 then
|
||||
# The union of a single tree simply returns the first element
|
||||
head trees
|
||||
else
|
||||
let
|
||||
# Like lib.findFirstIndex but without indexing.
|
||||
# This is a hot path so the indexing arithmetic adds up.
|
||||
firstStr = foldl' (
|
||||
found: tree:
|
||||
if found != null then
|
||||
found
|
||||
else if isString tree then
|
||||
tree
|
||||
else
|
||||
found # null
|
||||
) null trees;
|
||||
nonNulls = filter (tree: tree != null) trees;
|
||||
in
|
||||
let
|
||||
stringIndex = findFirstIndex isString null trees;
|
||||
withoutNull = filter (tree: tree != null) trees;
|
||||
in
|
||||
if stringIndex != null then
|
||||
# If there's a string, it's always a fully included tree (dir or file),
|
||||
# no need to look at other elements
|
||||
if firstStr != null then
|
||||
firstStr
|
||||
else if nonNulls == [ ] then
|
||||
null
|
||||
else
|
||||
# The non-null elements have to be attribute sets representing partial trees
|
||||
# We need to recurse into those
|
||||
zipAttrsWith (name: _unionTrees) nonNulls;
|
||||
elemAt trees stringIndex
|
||||
else if withoutNull == [ ] then
|
||||
# If all trees are null, then the resulting tree is also null
|
||||
null
|
||||
else
|
||||
# The non-null elements have to be attribute sets representing partial trees
|
||||
# We need to recurse into those
|
||||
zipAttrsWith (name: _unionTrees) withoutNull;
|
||||
|
||||
/**
|
||||
Computes the intersection of two filesets.
|
||||
|
||||
@@ -203,11 +203,6 @@ lib.mapAttrs mkLicense (
|
||||
fullName = " BitTorrent Open Source License v1.1";
|
||||
};
|
||||
|
||||
blessing = {
|
||||
spdxId = "blessing";
|
||||
fullName = "SQLite Blessing";
|
||||
};
|
||||
|
||||
boehmGC = {
|
||||
spdxId = "Boehm-GC";
|
||||
fullName = "Boehm-Demers-Weiser GC License";
|
||||
@@ -1622,13 +1617,6 @@ lib.mapAttrs mkLicense (
|
||||
fullName = "Universal Permissive License";
|
||||
};
|
||||
|
||||
valveSDK = {
|
||||
fullName = "Valve Corporation Steamworks SDK Access Agreement";
|
||||
url = "https://partner.steamgames.com/documentation/sdk_access_agreement";
|
||||
free = false;
|
||||
redistributable = true;
|
||||
};
|
||||
|
||||
vim = {
|
||||
spdxId = "Vim";
|
||||
fullName = "Vim License";
|
||||
|
||||
@@ -151,24 +151,7 @@ let
|
||||
);
|
||||
|
||||
# Derived meta-data
|
||||
useLLVM =
|
||||
final.isFreeBSD
|
||||
|| final.isOpenBSD
|
||||
|| final.isUefi
|
||||
|| final.isMsvc
|
||||
||
|
||||
# because GCC does not support this platform yet
|
||||
(with final; isWindows && isAarch64);
|
||||
|
||||
# Use the split GCC package set (`gccNGPackages`) instead of the
|
||||
# monolithic `gcc`. No platform selects it yet; it is opt-in, set
|
||||
# explicitly on a platform spec, so that the split set can be exercised
|
||||
# before anything depends on it.
|
||||
#
|
||||
# I (@Ericson2314) plan on making obscure low-tier platforms (e.g.
|
||||
# NetBSD) use it soon, so we can dogfood GCC NG and thereby iron out its
|
||||
# bugs.
|
||||
useGccNG = false;
|
||||
useLLVM = final.isFreeBSD || final.isOpenBSD;
|
||||
|
||||
libc =
|
||||
if final.isDarwin then
|
||||
@@ -193,7 +176,9 @@ let
|
||||
"uclibc"
|
||||
else if final.isAndroid then
|
||||
"bionic"
|
||||
else if final.isLinux then
|
||||
else if
|
||||
final.isLinux # default
|
||||
then
|
||||
"glibc"
|
||||
else if final.isFreeBSD then
|
||||
"fblibc"
|
||||
@@ -205,8 +190,6 @@ let
|
||||
"avrlibc"
|
||||
else if final.isGhcjs then
|
||||
null
|
||||
else if final.isUefi then
|
||||
null
|
||||
else if final.isNone then
|
||||
"newlib"
|
||||
# TODO(@Ericson2314) think more about other operating systems
|
||||
|
||||
@@ -93,6 +93,7 @@ rec {
|
||||
config = "aarch64-unknown-linux-android";
|
||||
androidSdkVersion = "35";
|
||||
androidNdkVersion = "27";
|
||||
libc = "bionic";
|
||||
useAndroidPrebuilt = false;
|
||||
useLLVM = true;
|
||||
};
|
||||
@@ -168,18 +169,22 @@ rec {
|
||||
|
||||
riscv64-embedded = {
|
||||
config = "riscv64-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
riscv32-embedded = {
|
||||
config = "riscv32-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
mips64-embedded = {
|
||||
config = "mips64-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
mips-embedded = {
|
||||
config = "mips-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
# https://github.com/loongson/la-softdev-convention/blob/master/la-softdev-convention.adoc#10-operating-system-package-build-requirements
|
||||
@@ -196,17 +201,17 @@ rec {
|
||||
|
||||
mmix = {
|
||||
config = "mmix-unknown-mmixware";
|
||||
# Not `isNone`: the OS here is `mmixware`, so the bare-metal default does
|
||||
# not apply.
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
rx-embedded = {
|
||||
config = "rx-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
msp430 = {
|
||||
config = "msp430-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
avr = {
|
||||
@@ -215,10 +220,12 @@ rec {
|
||||
|
||||
vc4 = {
|
||||
config = "vc4-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
or1k = {
|
||||
config = "or1k-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
m68k = {
|
||||
@@ -243,6 +250,7 @@ rec {
|
||||
|
||||
arm-embedded = {
|
||||
config = "arm-none-eabi";
|
||||
libc = "newlib";
|
||||
};
|
||||
arm-embedded-nano = {
|
||||
config = "arm-none-eabi";
|
||||
@@ -250,6 +258,7 @@ rec {
|
||||
};
|
||||
armhf-embedded = {
|
||||
config = "arm-none-eabihf";
|
||||
libc = "newlib";
|
||||
# GCC8+ does not build without this
|
||||
# (https://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg552339.html):
|
||||
gcc = {
|
||||
@@ -260,31 +269,38 @@ rec {
|
||||
|
||||
aarch64-embedded = {
|
||||
config = "aarch64-none-elf";
|
||||
libc = "newlib";
|
||||
rust.rustcTarget = "aarch64-unknown-none";
|
||||
};
|
||||
|
||||
aarch64be-embedded = {
|
||||
config = "aarch64_be-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
ppc-embedded = {
|
||||
config = "powerpc-none-eabi";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
ppcle-embedded = {
|
||||
config = "powerpcle-none-eabi";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
i686-embedded = {
|
||||
config = "i686-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
x86_64-embedded = {
|
||||
config = "x86_64-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
microblaze-embedded = {
|
||||
config = "microblazeel-none-elf";
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
#
|
||||
@@ -322,10 +338,16 @@ rec {
|
||||
|
||||
x86_64-unknown-uefi = {
|
||||
config = "x86_64-unknown-uefi";
|
||||
libc = null;
|
||||
useLLVM = true;
|
||||
linker = "lld";
|
||||
};
|
||||
|
||||
aarch64-unknown-uefi = {
|
||||
config = "aarch64-unknown-uefi";
|
||||
libc = null;
|
||||
useLLVM = true;
|
||||
linker = "lld";
|
||||
};
|
||||
|
||||
#
|
||||
@@ -360,11 +382,12 @@ rec {
|
||||
};
|
||||
|
||||
# mingw-w64 with ucrt for Aarch64, default compiler (which is LLVM
|
||||
# see ./default.nix).
|
||||
# because GCC does not support this platform yet).
|
||||
mingw-ucrt-aarch64 = {
|
||||
config = "aarch64-w64-mingw32";
|
||||
libc = "ucrt";
|
||||
rust.rustcTarget = "aarch64-pc-windows-gnullvm";
|
||||
useLLVM = true;
|
||||
};
|
||||
|
||||
# mingw-64 back compat
|
||||
@@ -377,10 +400,12 @@ rec {
|
||||
# Target the MSVC ABI
|
||||
x86_64-windows = {
|
||||
config = "x86_64-pc-windows-msvc";
|
||||
useLLVM = true;
|
||||
};
|
||||
|
||||
aarch64-windows = {
|
||||
config = "aarch64-pc-windows-msvc";
|
||||
useLLVM = true;
|
||||
};
|
||||
|
||||
x86_64-cygwin = {
|
||||
@@ -391,10 +416,12 @@ rec {
|
||||
|
||||
aarch64-freebsd = {
|
||||
config = "aarch64-unknown-freebsd";
|
||||
useLLVM = true;
|
||||
};
|
||||
|
||||
x86_64-freebsd = {
|
||||
config = "x86_64-unknown-freebsd";
|
||||
useLLVM = true;
|
||||
};
|
||||
|
||||
x86_64-netbsd = {
|
||||
|
||||
@@ -63,12 +63,6 @@
|
||||
{
|
||||
# keep-sorted start case=no numeric=no block=yes
|
||||
|
||||
"3mp3ri0r" = {
|
||||
email = "christoforus@xendit.co";
|
||||
github = "3mp3ri0r";
|
||||
githubId = 3140815;
|
||||
name = "Christoforus Surjoputro";
|
||||
};
|
||||
_0b11stan = {
|
||||
name = "Tristan Auvinet Pinaudeau";
|
||||
email = "tristan@tic.sh";
|
||||
@@ -295,11 +289,6 @@
|
||||
name = "6543";
|
||||
keys = [ { fingerprint = "8722 B61D 7234 1082 553B 201C B8BE 6D61 0E61 C862"; } ];
|
||||
};
|
||||
_66HEX = {
|
||||
name = "Marek Jóźwiak";
|
||||
github = "66HEX";
|
||||
githubId = 168720167;
|
||||
};
|
||||
_6AA4FD = {
|
||||
email = "f6442954@gmail.com";
|
||||
github = "6AA4FD";
|
||||
@@ -627,11 +616,6 @@
|
||||
{ fingerprint = "CE85 54F7 B9BC AC0D D648 5661 AB5F C04C 3C94 443F"; }
|
||||
];
|
||||
};
|
||||
ad-si = {
|
||||
name = "Adrian Sieber";
|
||||
github = "ad-si";
|
||||
githubId = 36796532;
|
||||
};
|
||||
ad030 = {
|
||||
name = "Alex Dam";
|
||||
github = "ad030";
|
||||
@@ -891,12 +875,6 @@
|
||||
githubId = 6055037;
|
||||
name = "Alexander Hirner";
|
||||
};
|
||||
AhmedAmr = {
|
||||
email = "ahmedamr24680@gmail.com";
|
||||
github = "AhmedAmrNabil";
|
||||
githubId = 43810060;
|
||||
name = "Ahmed Amr";
|
||||
};
|
||||
ahoneybun = {
|
||||
email = "aaronhoneycutt@proton.me";
|
||||
github = "ahoneybun";
|
||||
@@ -1450,11 +1428,6 @@
|
||||
githubId = 30437811;
|
||||
name = "Alex Andrews";
|
||||
};
|
||||
alikaansun = {
|
||||
github = "alikaansun";
|
||||
githubId = 77810345;
|
||||
name = "Ali Kaan Sunnetcioglu";
|
||||
};
|
||||
alikindsys = {
|
||||
email = "alice@blocovermelho.org";
|
||||
github = "alikindsys";
|
||||
@@ -2352,12 +2325,6 @@
|
||||
githubId = 8049011;
|
||||
name = "Arik Grahl";
|
||||
};
|
||||
arison = {
|
||||
email = "arison@duck.com";
|
||||
github = "ArisoN-ext";
|
||||
githubId = 181835726;
|
||||
name = "ArisoN";
|
||||
};
|
||||
ariutta = {
|
||||
email = "anders.riutta@gmail.com";
|
||||
github = "ariutta";
|
||||
@@ -5188,11 +5155,6 @@
|
||||
githubId = 1103294;
|
||||
name = "Christopher Rosset";
|
||||
};
|
||||
christo-auer = {
|
||||
name = "Christopher Auer";
|
||||
github = "christo-auer";
|
||||
githubId = 15138131;
|
||||
};
|
||||
christoph-heiss = {
|
||||
email = "christoph@c8h4.io";
|
||||
github = "christoph-heiss";
|
||||
@@ -7161,12 +7123,6 @@
|
||||
githubId = 15774340;
|
||||
name = "Thomas Depierre";
|
||||
};
|
||||
dibenzepin = {
|
||||
name = "Fumnanya";
|
||||
email = "fmowete@outlook.com";
|
||||
github = "dibenzepin";
|
||||
githubId = 87488715;
|
||||
};
|
||||
DictXiong = {
|
||||
email = "me@beardic.cn";
|
||||
github = "DictXiong";
|
||||
@@ -7608,6 +7564,12 @@
|
||||
githubId = 81854406;
|
||||
name = "Chew Cheng Hong";
|
||||
};
|
||||
drew-dirac = {
|
||||
email = "drew@diracinc.com";
|
||||
github = "drew-dirac";
|
||||
githubId = 187309685;
|
||||
name = "Drew Council";
|
||||
};
|
||||
drperceptron = {
|
||||
github = "drperceptron";
|
||||
githubId = 92106371;
|
||||
@@ -7787,8 +7749,7 @@
|
||||
matrix = "@dvdznf:gitter.im";
|
||||
};
|
||||
dvn0 = {
|
||||
email = "devan@informatics.coop";
|
||||
keys = [ { fingerprint = "E0F4 87C6 6298 7353 A7D0 E997 8203 BD5C 41D8 29DF"; } ];
|
||||
email = "git@dvn.me";
|
||||
github = "dvn0";
|
||||
githubId = 10859387;
|
||||
name = "Devan Carpenter";
|
||||
@@ -8151,13 +8112,6 @@
|
||||
githubId = 7494394;
|
||||
name = "Karim Elatov";
|
||||
};
|
||||
eldios = {
|
||||
email = "emanuele.lele.calo@gmail.com";
|
||||
github = "eldios";
|
||||
githubId = 483767;
|
||||
name = "Emanuele 'Lele' Calo";
|
||||
keys = [ { fingerprint = "AA6B C774 3F8F 9AD8 4BBA 15C7 2CCB F4B7 1EFF DD46"; } ];
|
||||
};
|
||||
eleanor = {
|
||||
email = "dejan@proteansec.com";
|
||||
github = "proteansec";
|
||||
@@ -8804,12 +8758,6 @@
|
||||
githubId = 330292;
|
||||
name = "Evan Richter";
|
||||
};
|
||||
evanwporter = {
|
||||
email = "evanwporter@gmail.com";
|
||||
github = "evanwporter";
|
||||
githubId = 115374841;
|
||||
name = "Evan Porter";
|
||||
};
|
||||
evax = {
|
||||
email = "nixos@evax.fr";
|
||||
github = "evax";
|
||||
@@ -10132,11 +10080,6 @@
|
||||
name = "Kirill Samoylenkov";
|
||||
keys = [ { fingerprint = "955B 97C5 78A3 DF03 D818 25EB 8E40 5DD2 CF84 CCE0"; } ];
|
||||
};
|
||||
gefla = {
|
||||
name = "Gerd Flaig";
|
||||
github = "gefla";
|
||||
githubId = 56790;
|
||||
};
|
||||
genga898 = {
|
||||
email = "genga898@gmail.com";
|
||||
github = "genga898";
|
||||
@@ -10183,12 +10126,7 @@
|
||||
github = "gepbird";
|
||||
githubId = 29818440;
|
||||
name = "Gutyina Gergő";
|
||||
matrix = "@gepbird:matrix.org";
|
||||
keys = [
|
||||
{ fingerprint = "hEzYpII9pUMfbhhr1LbUaLoGKGKX7UJQ1i9QU5SIssQ"; }
|
||||
{ fingerprint = "MnieeyZ1Y02OB4PMrkM5xrk3ZXq3XTahcSocDyqzmFg"; }
|
||||
{ fingerprint = "YfsHXlTvwc3HmLzQPi4g9nn4bKCj/mV/xgg9dxxxdnU"; }
|
||||
{ fingerprint = "2NGbD6uF4OYtqjaYvN4foZFooT7XTAHODUaNxGVuJdk"; }
|
||||
{ fingerprint = "RoAfvqa6w1l8Vdm3W60TDXurYwJ6h03VEGD+wDNGEwc"; }
|
||||
{ fingerprint = "MP2UpIRtJpbFFqyucP431H/FPCfn58UhEUTro4lXtRs"; }
|
||||
];
|
||||
@@ -11335,6 +11273,11 @@
|
||||
githubId = 58676303;
|
||||
name = "hhydraa";
|
||||
};
|
||||
hibiday = {
|
||||
name = "Katsumi Takeuchi";
|
||||
github = "hibiday";
|
||||
githubId = 137286929;
|
||||
};
|
||||
higebu = {
|
||||
name = "Yuya Kusakabe";
|
||||
email = "yuya.kusakabe@gmail.com";
|
||||
@@ -12520,13 +12463,6 @@
|
||||
githubId = 7558482;
|
||||
name = "Jack Gerrits";
|
||||
};
|
||||
jackoe = {
|
||||
name = "Jack Wines";
|
||||
email = "nixos@winesj.com";
|
||||
github = "jackoe";
|
||||
githubId = 3060163;
|
||||
matrix = "@noiobeforebedtime:winesj.com";
|
||||
};
|
||||
jackr = {
|
||||
name = "Jack Rosenberg";
|
||||
email = "nixos@jackr.eu";
|
||||
@@ -13646,12 +13582,6 @@
|
||||
githubId = 32305209;
|
||||
name = "John Children";
|
||||
};
|
||||
johnhamelink = {
|
||||
email = "me@johnhame.link";
|
||||
github = "johnhamelink";
|
||||
githubId = 101739;
|
||||
name = "John Hamelink";
|
||||
};
|
||||
johnjohnstone = {
|
||||
email = "jjohnstone@riseup.net";
|
||||
github = "johnjohnstone";
|
||||
@@ -16192,11 +16122,7 @@
|
||||
};
|
||||
liamthexpl0rer = {
|
||||
name = "Liam";
|
||||
matrix = "@liamthexpl0rer:l14mx.de";
|
||||
keys = [
|
||||
{ fingerprint = "3C0A 0FC8 E406 E602 50F3 FCFD 7633 7F2C A1CB 537D"; }
|
||||
{ fingerprint = "CC53 895B 3CC7 7B29 AA46 55EF 6DF0 2F41 092A 9B30"; }
|
||||
];
|
||||
matrix = "@liamthexpl0rer:matrix.org";
|
||||
github = "liamthexpl0rer";
|
||||
githubId = 119797945;
|
||||
};
|
||||
@@ -17000,13 +16926,6 @@
|
||||
}
|
||||
];
|
||||
};
|
||||
lunkentuss = {
|
||||
email = "peter.hansson17@gmail.com";
|
||||
matrix = "@lunkentuss:matrix.org";
|
||||
github = "lunkentuss";
|
||||
githubId = 9850798;
|
||||
name = "Peter Hansson";
|
||||
};
|
||||
LunNova = {
|
||||
email = "nixpkgs-maintainer@lunnova.dev";
|
||||
github = "LunNova";
|
||||
@@ -17044,17 +16963,6 @@
|
||||
matrix = "@lux:ontheblueplanet.com";
|
||||
name = "Lux";
|
||||
};
|
||||
luytan = {
|
||||
email = "luytan@khora.me";
|
||||
github = "luytan";
|
||||
githubId = 221864923;
|
||||
name = "Luytan";
|
||||
keys = [
|
||||
{
|
||||
fingerprint = "E7B7 215C 0DFB 3D8C 17EE 95E0 E0AD 187A 4F2B 41EF";
|
||||
}
|
||||
];
|
||||
};
|
||||
luz = {
|
||||
email = "luz666@daum.net";
|
||||
github = "Luz";
|
||||
@@ -18949,12 +18857,6 @@
|
||||
githubId = 54669781;
|
||||
keys = [ { fingerprint = "293B 93D8 A471 059F 85D7 16A6 5BA9 2099 D9BE 2DAA"; } ];
|
||||
};
|
||||
mishushakov = {
|
||||
email = "mish@e2b.dev";
|
||||
github = "mishushakov";
|
||||
githubId = 10400064;
|
||||
name = "Mish Ushakov";
|
||||
};
|
||||
misilelab = {
|
||||
name = "misilelab";
|
||||
email = "misileminecord@gmail.com";
|
||||
@@ -19321,13 +19223,6 @@
|
||||
matrix = "@motiejus:jakstys.lt";
|
||||
name = "Motiejus Jakštys";
|
||||
};
|
||||
Mowerick = {
|
||||
email = "oliverhagenauer@gmail.com";
|
||||
github = "Mowerick";
|
||||
githubId = 102822250;
|
||||
keys = [ { fingerprint = "6472 901A F0E7 F983 4893 042F 5F76 361C 2EF9 C95F"; } ];
|
||||
name = "Oliver Hagenauer";
|
||||
};
|
||||
mpcsh = {
|
||||
email = "m@mpc.sh";
|
||||
github = "mpcsh";
|
||||
@@ -20615,12 +20510,6 @@
|
||||
githubId = 70602908;
|
||||
github = "nikolaizombie1";
|
||||
};
|
||||
nikp123 = {
|
||||
name = "nikp123";
|
||||
email = "nikp123@e.email";
|
||||
github = "nikp123";
|
||||
githubId = 4696350;
|
||||
};
|
||||
nikstur = {
|
||||
email = "nikstur@outlook.com";
|
||||
name = "nikstur";
|
||||
@@ -21889,12 +21778,6 @@
|
||||
githubId = 4908217;
|
||||
name = "Paho Lurie-Gregg";
|
||||
};
|
||||
paige = {
|
||||
email = "paigely@tuta.io";
|
||||
github = "ssalggnikool";
|
||||
githubId = 235818692;
|
||||
name = "paige";
|
||||
};
|
||||
pakhfn = {
|
||||
email = "pakhfn@gmail.com";
|
||||
github = "pakhfn";
|
||||
@@ -22924,6 +22807,12 @@
|
||||
githubId = 4201956;
|
||||
name = "pongo1231";
|
||||
};
|
||||
poopsicles = {
|
||||
name = "Fumnanya";
|
||||
email = "fmowete@outlook.com";
|
||||
github = "dibenzepin";
|
||||
githubId = 87488715;
|
||||
};
|
||||
PopeRigby = {
|
||||
name = "PopeRigby";
|
||||
github = "poperigby";
|
||||
@@ -23652,13 +23541,6 @@
|
||||
github = "rachalaraj";
|
||||
githubId = 124191100;
|
||||
};
|
||||
rachitvrma = {
|
||||
name = "Rachit Kumar Verma";
|
||||
email = "rachitverma1122+nixpkgs@gmail.com";
|
||||
matrix = "@rachitvrma:matrix.org";
|
||||
github = "rachitvrma";
|
||||
githubId = 155641117;
|
||||
};
|
||||
RadxaYuntian = {
|
||||
# This is the work account for @MakiseKurisu
|
||||
name = "ZHANG Yuntian";
|
||||
@@ -23967,12 +23849,6 @@
|
||||
name = "Roland Conybeare";
|
||||
keys = [ { fingerprint = "bw5Cr/4ul1C2UvxopphbZbFI1i5PCSnOmPID7mJ/Ogo"; } ];
|
||||
};
|
||||
rdk31 = {
|
||||
email = "nixpkgs@rdk31.com";
|
||||
github = "rdk31";
|
||||
githubId = 16737959;
|
||||
name = "rdk31";
|
||||
};
|
||||
rdnetto = {
|
||||
email = "rdnetto@gmail.com";
|
||||
github = "rdnetto";
|
||||
@@ -23996,12 +23872,6 @@
|
||||
{ fingerprint = "01D7 5486 3A6D 64EA AC77 0D26 FBF1 9A98 2CCE 0048"; }
|
||||
];
|
||||
};
|
||||
recutita = {
|
||||
name = "Katsumi Takeuchi";
|
||||
email = "contact@recutita.com";
|
||||
github = "recutita";
|
||||
githubId = 137286929;
|
||||
};
|
||||
redfish64 = {
|
||||
email = "engler@gmail.com";
|
||||
github = "redfish64";
|
||||
@@ -32012,12 +31882,6 @@
|
||||
githubId = 3449926;
|
||||
name = "David Costa";
|
||||
};
|
||||
ZariTen = {
|
||||
email = "ZaritenProt@proton.me";
|
||||
github = "ZariTen";
|
||||
githubId = 48529745;
|
||||
name = "ZariTen";
|
||||
};
|
||||
zatm8 = {
|
||||
email = "maxis1191@gmail.com";
|
||||
github = "mourogurt";
|
||||
|
||||
@@ -23,7 +23,6 @@ digestif,,,,,5.3,
|
||||
dkjson,,,,,,
|
||||
enet,,,,,,ulysseszhan
|
||||
etlua,,,,,,ulysseszhan
|
||||
fallo,,,,,,mrcjkb
|
||||
fennel,,,,,,misterio77
|
||||
fidget.nvim,,,,,5.1,mrcjkb
|
||||
fifo,,,,,,
|
||||
|
||||
|
@@ -10,9 +10,6 @@ stdenv.mkDerivation {
|
||||
pname = "nixpkgs-lint";
|
||||
version = "1";
|
||||
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
buildInputs = [
|
||||
perl
|
||||
@@ -23,20 +20,16 @@ stdenv.mkDerivation {
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/bin
|
||||
cp ${./nixpkgs-lint.pl} $out/bin/nixpkgs-lint
|
||||
# make the built version hermetic
|
||||
substituteInPlace $out/bin/nixpkgs-lint \
|
||||
--replace-fail "#! /usr/bin/env nix-shell" "#! ${lib.getExe perl}"
|
||||
wrapProgram $out/bin/nixpkgs-lint --set PERL5LIB $PERL5LIB
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Utility for Nixpkgs contributors to check Nixpkgs for common errors";
|
||||
description = "A utility for Nixpkgs contributors to check Nixpkgs for common errors";
|
||||
mainProgram = "nixpkgs-lint";
|
||||
platforms = lib.platforms.unix;
|
||||
};
|
||||
|
||||
@@ -402,7 +402,6 @@ with lib.maintainers;
|
||||
GaetanLepage
|
||||
natsukium
|
||||
thomasjm
|
||||
haansn08
|
||||
];
|
||||
scope = "Maintain Jupyter and related packages.";
|
||||
shortName = "Jupyter";
|
||||
@@ -711,6 +710,7 @@ with lib.maintainers;
|
||||
|
||||
sage = {
|
||||
members = [
|
||||
timokau
|
||||
raskin
|
||||
collares
|
||||
];
|
||||
|
||||
@@ -395,7 +395,7 @@ have a predefined type and string generator already declared under
|
||||
|
||||
`mkRaw pythonCode`
|
||||
|
||||
: Outputs the given string as raw Python code. Note that the final result will be stripped of any comments.
|
||||
: Outputs the given string as raw Python code
|
||||
|
||||
`_imports`
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# State revision {#sec-state-revision}
|
||||
|
||||
NixOS includes a {option}`system.stateVersion` option, used by some modules for a
|
||||
variety of reasons related to non-backward-compatible changes to software or
|
||||
the module itself.
|
||||
Module authors are discouraged from adding new uses of
|
||||
{option}`system.stateVersion` to their module.
|
||||
|
||||
However, when the alternatives are impractical, modules that wish to consume
|
||||
{option}`system.stateVersion` should instead define their own `stateRevision`
|
||||
option using `utils.mkStateRevisionOption`.
|
||||
There should be no uses of `config.system.stateVersion` directly in the module.
|
||||
|
||||
(Note the name difference: the {option}`system.stateVersion` option, with a V,
|
||||
takes a value that looks like "YY.MM".
|
||||
A `stateRevision` option, with an R, takes a non-negative integer value.)
|
||||
|
||||
Modules should also add the value of their `stateRevision` option to
|
||||
`system.moduleStateRevisions."your.module.stateRevision"`, when the module is
|
||||
enabled.
|
||||
This is a purely informative option that exists to help describe the effects of
|
||||
changing {option}`system.stateVersion`.
|
||||
|
||||
Example:
|
||||
|
||||
```nix
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.whatever;
|
||||
in
|
||||
{
|
||||
options.services.whatever = {
|
||||
enable = lib.mkEnableOption "whatever, a service that does whatever";
|
||||
stateRevision = utils.mkStateRevisionOption {
|
||||
descriptionName = "the whatever service";
|
||||
migrations = {
|
||||
"26.05" = "Rename `/var/lib/old_name` to `/var/lib/new_name`.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.whatever = {
|
||||
# ...
|
||||
serviceConfig.StateDirectory = if cfg.stateRevision < 1 then "old_name" else "new_name";
|
||||
};
|
||||
|
||||
# Important: this is inside the `lib.mkIf cfg.enable`
|
||||
system.moduleStateRevisions."services.whatever.stateRevision" = cfg.stateRevision;
|
||||
};
|
||||
}
|
||||
```
|
||||
@@ -220,5 +220,4 @@ importing-modules.section.md
|
||||
replace-modules.section.md
|
||||
freeform-modules.section.md
|
||||
settings-options.section.md
|
||||
state-revision.section.md
|
||||
```
|
||||
|
||||
@@ -41,22 +41,8 @@ supported stable release.
|
||||
When you first install NixOS, you're automatically subscribed to the
|
||||
NixOS channel that corresponds to your installation source. For
|
||||
instance, if you installed from a 26.05 ISO, you will be subscribed to
|
||||
the `nixos-26.05` channel.
|
||||
|
||||
Commands below are prefixed with `#` and have to be run as root in a
|
||||
login shell:
|
||||
|
||||
```ShellSession
|
||||
$ sudo -i
|
||||
```
|
||||
|
||||
Without `sudo`:
|
||||
|
||||
```ShellSession
|
||||
$ su -
|
||||
```
|
||||
|
||||
To see which NixOS channel you're subscribed to, run:
|
||||
the `nixos-26.05` channel. To see which NixOS channel you're subscribed
|
||||
to, run the following as root:
|
||||
|
||||
```ShellSession
|
||||
# nix-channel --list | grep nixos
|
||||
@@ -98,15 +84,9 @@ by running
|
||||
which is equivalent to the more verbose `nix-channel --update nixos; nixos-rebuild switch`.
|
||||
|
||||
::: {.note}
|
||||
Channels are set per user. `nix-channel` reads and writes
|
||||
`$HOME/.nix-channels`, so it acts on the channels of whoever owns the
|
||||
current `$HOME`. A login shell sets `$HOME` to `/root`, which is why the
|
||||
commands above act on root's channels — the ones
|
||||
`/etc/nixos/configuration.nix` uses.
|
||||
|
||||
Plain `sudo` and `su` keep your own `$HOME`. `nix-channel --list` then
|
||||
lists your own channels, and prints nothing when you have none.
|
||||
`nix-channel --add` adds the channel for your user alone.
|
||||
Channels are set per user. This means that running `nix-channel --add`
|
||||
as a non root user (or without sudo) will not affect
|
||||
configuration in `/etc/nixos/configuration.nix`
|
||||
:::
|
||||
|
||||
::: {.warning}
|
||||
|
||||
@@ -7,5 +7,5 @@ Additional information regarding the Nix package manager and the Nixpkgs project
|
||||
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.
|
||||
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.
|
||||
:::
|
||||
|
||||
@@ -253,9 +253,6 @@
|
||||
"sec-override-nixos-test": [
|
||||
"index.html#sec-override-nixos-test"
|
||||
],
|
||||
"sec-state-revision": [
|
||||
"index.html#sec-state-revision"
|
||||
],
|
||||
"sec-wireless-declarative": [
|
||||
"index.html#sec-wireless-declarative"
|
||||
],
|
||||
|
||||
@@ -28,14 +28,8 @@
|
||||
firewall, is available through
|
||||
[services.portmaster](#opt-services.portmaster.enable).
|
||||
|
||||
- [btrfs-heatmap](https://github.com/knorrie/btrfs-heatmap), setcap wrapper for `btrfs-heatmap` package, a visualizer of how a btrfs filesystem is using the underlying disk space of the block devices. Available as [programs.btrfs-heatmap](#opt-programs.btrfs-heatmap.enable)
|
||||
|
||||
- [compsize](https://github.com/kilobyte/compsize), setcap wrapper for `compsize` package, a cli utility to to inspect compression type/ratio on BTRFS filesystems. Available as [programs.compsize](#opt-programs.compsize.enable)
|
||||
|
||||
- [tranquil](https://tangled.org/tranquil.farm/tranquil-pds) is an ATProto PDS (personal data server) implementation in Rust. A featureful, spec conscious and community driven alternative to the Bluesky reference implementation PDS. Available as [services.tranquil-pds](#opt-services.tranquil-pds.enable).
|
||||
|
||||
- [Cardwire](https://github.com/OpenGamingCollective/cardwire), a GPU manager for Linux that uses eBPF+LSM hooks to control GPUs. Available as [services.cardwired](#opt-services.cardwired.enable).
|
||||
|
||||
- [Moonlight Qt](https://moonlight-stream.org/), a client for playing your PC games on almost any device. Available as [programs.moonlight-qt](#opt-programs.moonlight-qt.enable).
|
||||
|
||||
- [RomM](https://romm.app/), a self-hosted ROM manager and player. Available as [services.romm](#opt-services.romm.enable).
|
||||
@@ -64,14 +58,10 @@
|
||||
|
||||
- [Lix TOML remote builders](https://docs.lix.systems/manual/lix/stable/advanced-topics/distributed-builds.html#using-a-toml-configuration), remote builder configuration using lix's TOML format. Available as [lix.buildMachines](#opt-lix.buildMachines). Note: incompatible with `nix.buildMachines`.
|
||||
|
||||
- [Forgejo Runner](https://forgejo.org/docs/latest/admin/actions/), a daemon for Forgejo Actions. Available as [services.forgejo-runner](#opt-services.forgejo-runner.instances).
|
||||
|
||||
- [Koito](https://koito.io/), a modern, themeable scrobbler that you can use with any program that scrobbles to a custom ListenBrainz URL. Available as [services.koito](#opt-services.koito.enable).
|
||||
|
||||
- [Zapret2](https://github.com/bol-van/zapret2), an extensible DPI bypass program. Available as [services.zapret2](#opt-services.zapret2.enable).
|
||||
|
||||
- [Solaar](https://github.com/pwr-Solaar/Solaar), a program to control logitech devices.
|
||||
|
||||
- [FlapAlerted](https://github.com/Kioubit/FlapAlerted), detects BGP flapping events and provides statistics based on BGP update messages. Available as [services.flap-alerted](#opt-services.flap-alerted.enable).
|
||||
|
||||
- [gocron](https://github.com/flohoss/gocron), a task scheduler with web interface. Available as [services.gocron](#opt-services.gocron.enable).
|
||||
@@ -82,8 +72,6 @@
|
||||
|
||||
- [Matrix Authentication Service](https://github.com/element-hq/matrix-authentication-service) is an OAuth2.0 and OpenID Connect provider for Matrix homeservers (such as Synapse). It replaces standard password authentication with modern OpenID Connect flows, and can delegate authentication to upstream OIDC providers. Available as [services.matrix-authentication-service](#opt-services.matrix-authentication-service.enable).
|
||||
|
||||
- [Krill](https://nlnetlabs.nl/projects/krill/about), RPKI CA and Publication Server written in Rust. Available as [services.krill](#opt-services.krill.enable).
|
||||
|
||||
- [stash-clipboard](https://github.com/NotAShelf/stash), a Wayland clipboard "manager" with fast persistent history and multi-media support. Available as [services.stash-clipboard](#opt-services.stash-clipboard.enable).
|
||||
|
||||
- [OO7](https://github.com/linux-credentials/oo7) is a desktop-agnostic Secret Service provider. Available as [services.oo7](#opt-services.oo7.enable)
|
||||
@@ -96,10 +84,6 @@
|
||||
|
||||
- [Entropy](https://github.com/ergohaven/entropy), a configurator for programmable keyboards and input devices running Vial-QMK/RMK firmware. Available as [programs.entropy](#opt-programs.entropy.enable).
|
||||
|
||||
- [Kvrocks](https://kvrocks.apache.org/), a distributed key value NoSQL database compatible with the Redis protocol. Available as [services.kvrocks](#opt-services.kvrocks.enable).
|
||||
|
||||
- [kvrocks_exporter](https://github.com/RocksLabs/kvrocks_exporter), a Prometheus exporter for Kvrocks metrics. Available as [services.prometheus.exporters.kvrocks](#opt-services.prometheus.exporters.kvrocks.enable).
|
||||
|
||||
## Backward Incompatibilities {#sec-release-26.11-incompatibilities}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
@@ -134,8 +118,6 @@
|
||||
|
||||
- Rustical migrates from `settings.http.host` and `settings.http.port` to `settings.http.bind` to support UNIX domain sockets as well as TCP sockets in one setting.
|
||||
|
||||
- The `jetty_11` package has been removed as it reached end of life. Use `jetty_12` instead.
|
||||
|
||||
- The Mullvad VPN service now has a separate toggle to enable the Mullvad VPN graphical user interface. If you have previously used Mullvad on a desktop by setting `services.mullvad-vpn.package` to `pkgs.mullvad-vpn`, you should now **unset that option**, and enable `services.mullvad-vpn.gui.enable`. The VPN will not work if `services.mullvad-vpn.package` is set to `pkgs.mullvad-vpn`, as `pkgs.mullvad-vpn` no longer contains the Mullvad Daemon; please ensure that `services.mullvad-vpn.package` is set to `pkgs.mullvad`, regardless if you plan to enable the graphical user interface or not.
|
||||
|
||||
- A number of options for `services.llama-cpp` have been removed in favor of the structured [](#opt-services.llama-cpp.settings) option, attributes from which are used as arguments to `llama-server` executable, you can see all available options by running `llama-server --help`. Configuring model presets using Nix attribute set via `services.llama-cpp.modelsPreset` is no longer supported, please use `services.llama-cpp.settings.models-preset` with a path to an INI file containing desired options.
|
||||
@@ -162,12 +144,8 @@
|
||||
|
||||
- String values passed to `services.phpfpm.settings`, `services.phpfpm.pools.<name>.phpEnv`, and `services.phpfpm.pools.<name>.settings` are now properly quoted and escaped, except for the `${}` syntax that is left as-is. If you are manually escaping these values, please adjust accordingly.
|
||||
|
||||
- GitLab has been updated from 18.x to 19.x and requires PostgreSQL >= 17, as stated in the [documentation](https://docs.gitlab.com/19.1/install/requirements/#postgresql). Check the [upgrade guide](#module-services-postgres-upgrading) in the NixOS manual on how to upgrade your PostgreSQL installation.
|
||||
|
||||
- `services.gitlab.registry` has been modified so that the GitLab container registry runs in the `gitlab-container-registry` system user. This behavior can be modified with the `services.gitlab.registry.user` option.
|
||||
|
||||
- `fail2ban` has been updated to 1.1.1, which has a few breaking changes compared to 1.1.0 ([changelog](https://github.com/fail2ban/fail2ban/blob/1.1.1/ChangeLog))
|
||||
|
||||
- `systemd.user.extraConfig` has been removed in favor of the structured [](#opt-systemd.user.settings.Manager) option. Use `systemd.user.settings.Manager` to set any `systemd-user.conf(5)` option directly. For example, replace `systemd.user.extraConfig = "DefaultTimeoutStartSec=60";` with `systemd.user.settings.Manager.DefaultTimeoutStartSec = 60;`.
|
||||
|
||||
- `matrix-appservice-discord` was removed from nixpkgs along with its NixOS module (`services.matrix-appservice-discord`) as it is no longer actively maintained upstream. Use the actively-maintained puppeting bridge [`mautrix-discord`](#opt-services.mautrix-discord.enable) instead.
|
||||
@@ -201,8 +179,6 @@
|
||||
- `temporal` has been updated to the 1.31 release line. Always consult the [upstream upgrade
|
||||
notes](https://docs.temporal.io/self-hosted-guide/upgrade-server) before upgrading between versions.
|
||||
|
||||
- The Xen Project Hypervisor has been [updated to version 4.22](https://wiki.xenproject.org/wiki/Xen_Project_4.22_Release_Notes), after [version 4.21](https://wiki.xenproject.org/wiki/Xen_Project_4.21_Release_Notes) was skipped in 26.05. The module now has a separate option to customise the OCaml-based Xen Store Daemon package, `virtualisation.xen.store.package`.
|
||||
|
||||
- The `shell_interact()` function on interactive runs of NixOS VM tests has been deprecated. Use the SSH backdoor instead.
|
||||
|
||||
- NixOS VM tests now prefer to express durations and timeouts as `datetime.timedelta` values instead of bare numbers. Methods such as `machine.wait_until_succeeds`, `machine.sleep`, `retry`, and `polling_condition` now accept a `timedelta` (e.g., `machine.wait_for_unit("sshd.service", timeout=datetime.timedelta(minutes=1))`). Passing an `int`/`float` as seconds still works but now emits a deprecation warning. Argument names that explicitly defined units were preserved but have had `timedelta` equivalents introduced (`timeout_seconds` → `timeout`, `secs` → `duration`, `seconds_interval` → `interval`).
|
||||
@@ -237,8 +213,6 @@
|
||||
|
||||
- `boot.supportedFilesystems.ntfs` installs `ntfsprogs-plus` instead of `ntfs3g` on kernel version 7.1 and later, unless `boot.supportedFilesystems.ntfs-3g` is explicitly enabled.
|
||||
|
||||
- `services.i2pd` has been refactored to take [RFC42](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md)-compliant `settings`. In order to migrate, you will need to move existing config under `settings` and rename them in accordance with the [upstream config format](https://docs.i2pd.website/en/latest/user-guide/configuration/#available-options). In addition, `inTunnels` and `outTunnels` needs to be renamed to `serverTunnels` and `clientTunnels` respectively.
|
||||
|
||||
- The `programs.fuse` module, which provides the `fusermount3` executable and the `/etc/fuse.conf` config file, is now opt-in. The obligation to enable it has been shifted to its various consumers (e.g. gvfs, flatpak, appimage, sshfs). This can break fuse consumers at runtime, that don't explicitly declare that dependency with a module, e.g the mounting functionality in various backup tools (borg, restic, rclone, ...).
|
||||
|
||||
- `services.plausible` can now again seed an initial admin user declaratively via [`services.plausible.adminUser.email`](#opt-services.plausible.adminUser.email).
|
||||
@@ -247,8 +221,6 @@
|
||||
|
||||
- `services.gitlab.registry` now uses PostgreSQL as database storage for new installations and supports old installations that use the filesystem as metadata storage. It creates the required PostgreSQL database and user. Users can manually migrate their filesystem based metadata storage. See [GitLab Container Registry Migration to database metadata store](#module-services-gitlab-registry-database-migration).
|
||||
|
||||
- Enabling [`services.userborn`](#opt-services.userborn.enable) on a system that was previously managed by the default `update-users-groups.pl` script now imports the legacy state from `/var/lib/nixos/` on the first switch. Locked stub entries are added to `/etc/passwd` and `/etc/group` for every name recorded in `uid-map`/`gid-map` that no longer has a live entry, so a previously-used UID/GID cannot be reassigned to a different user. If the import fails, userborn does not start and the user database is left untouched. Inspect `journalctl -u userborn-import-legacy.service`, fix or remove the legacy state, and switch again. The import can be skipped entirely with [`services.userborn.importLegacyState`](#opt-services.userborn.importLegacyState)` = false`.
|
||||
|
||||
- The `newuidmap` and `newgidmap` security wrappers are now installed with `cap_setuid`/`cap_setgid` file capabilities instead of the setuid-root bit, matching shadow's `--with-fcaps` install mode and other major distributions. Rootless containers (podman, docker-rootless, unprivileged user namespaces) are unaffected. The only behavioural change is that mapping host uid 0 via `/etc/subuid` (which NixOS never configures by default) additionally requires `cap_setfcap`; users who explicitly grant uid 0 in a subuid range can restore the previous behaviour with `security.wrappers.newuidmap.capabilities = lib.mkForce "cap_setuid,cap_setfcap+ep";`.
|
||||
|
||||
- The `authelia` module now uses systemd's `LoadCredential` to load all files defined in `secrets`. As such, these files no longer need to be readable by the authelia user and group: they can for example be set to be only readable by the root user.
|
||||
@@ -265,5 +237,3 @@
|
||||
- `trilium-desktop` and `trilium-server` have been updated to 0.104.0. This release includes security hardening fixes that may break functionality. [See upstream release note for details](https://github.com/TriliumNext/Trilium/releases/tag/v0.104.0).
|
||||
|
||||
- `nix` now supports running in "daemonless" mode by setting `nix.daemon.enable = false`. Under this mode all store operations must go through the [local store type](https://nix.dev/manual/nix/latest/store/types/local-store), which typically requires root permissions.
|
||||
|
||||
- [Hister](https://github.com/asciimoo/hister), a web history service offering blazing fast, content-based search across visited websites. Available as [services.hister](#opt-services.hister.enable).
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xorriso,
|
||||
syslinux,
|
||||
libossp_uuid,
|
||||
squashfs-tools,
|
||||
squashfsTools,
|
||||
|
||||
# The file name of the resulting ISO image.
|
||||
isoName ? "cd.iso",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
squashfs-tools,
|
||||
squashfsTools,
|
||||
closureInfo,
|
||||
|
||||
fileName ? "squashfs",
|
||||
@@ -31,7 +31,7 @@ stdenv.mkDerivation {
|
||||
# to the closure that was used to build it
|
||||
unsafeDiscardReferences.out = true;
|
||||
|
||||
nativeBuildInputs = [ squashfs-tools ];
|
||||
nativeBuildInputs = [ squashfsTools ];
|
||||
|
||||
buildCommand = ''
|
||||
closureInfo=${closureInfo { rootPaths = storeContents; }}
|
||||
|
||||
@@ -60,7 +60,7 @@ buildPythonApplication {
|
||||
util-linux
|
||||
vde2
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [
|
||||
++ lib.optionals stdenv.isLinux [
|
||||
vhost-device-vsock
|
||||
]
|
||||
++ lib.optionals enableNspawn [
|
||||
|
||||
@@ -8,12 +8,12 @@ testModuleArgs@{
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (types) either lines functionTo;
|
||||
inherit (types) either str functionTo;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
testScript = mkOption {
|
||||
type = either lines (functionTo lines);
|
||||
type = either str (functionTo str);
|
||||
apply =
|
||||
v:
|
||||
if lib.isFunction v then
|
||||
@@ -27,7 +27,7 @@ in
|
||||
'';
|
||||
};
|
||||
testScriptString = mkOption {
|
||||
type = lines;
|
||||
type = str;
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
};
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
all
|
||||
any
|
||||
attrNames
|
||||
concatImapStringsSep
|
||||
concatMapStringsSep
|
||||
concatStringsSep
|
||||
elem
|
||||
@@ -29,11 +27,8 @@ let
|
||||
isList
|
||||
isPath
|
||||
isString
|
||||
length
|
||||
listToAttrs
|
||||
literalMD
|
||||
mapAttrs
|
||||
mkOption
|
||||
nameValuePair
|
||||
optionalString
|
||||
removePrefix
|
||||
@@ -41,10 +36,8 @@ let
|
||||
splitString
|
||||
stringToCharacters
|
||||
types
|
||||
versionOlder
|
||||
;
|
||||
|
||||
inherit (lib.lists) findFirstIndex;
|
||||
inherit (lib.strings) toJSON escapeC;
|
||||
in
|
||||
|
||||
@@ -611,122 +604,6 @@ let
|
||||
lib.listToAttrs
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
Creates a per-module `stateRevision` option that takes an int value, with a
|
||||
default that is derived from `system.stateVersion`.
|
||||
|
||||
# Inputs
|
||||
|
||||
`descriptionName`
|
||||
: A human-friendly name for your module, used for the description of the
|
||||
created option.
|
||||
|
||||
`migrations`
|
||||
: Attribute set that maps from values of `system.stateVersion`
|
||||
(representing the breakpoints at which the default value of this option
|
||||
will change) to Markdown instructions to users for manually migrating
|
||||
their data to this breakpoint. The migration instructions will be
|
||||
included in the NixOS documentation for this option. (These instructions
|
||||
must only contain Markdown inlines, because they will be rendered as
|
||||
items in an ordered list. In particular, nested lists will not render
|
||||
correctly.)
|
||||
|
||||
`migrations` will also be exposed as an attribute on the result.
|
||||
|
||||
# Examples
|
||||
:::{.example}
|
||||
## `lib.options.mkStateRevisionOption` usage example
|
||||
|
||||
```nix
|
||||
exampleModule =
|
||||
{ lib, config, utils, ... }:
|
||||
{
|
||||
options.services.whatever = {
|
||||
stateRevision = utils.mkStateRevisionOption {
|
||||
descriptionName = "the whatever service";
|
||||
migrations = {
|
||||
"26.05" = "Rename `/var/lib/old_name` to `/var/lib/new_name`.";
|
||||
"26.11" = "Run the `upgrade_whatever` utility.";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
(pkgs.nixos [
|
||||
exampleModule
|
||||
{ system.stateVersion = "25.11"; }
|
||||
]).config.services.whatever.stateRevision # => 0
|
||||
(pkgs.nixos [
|
||||
exampleModule
|
||||
{ system.stateVersion = "26.05"; }
|
||||
]).config.services.whatever.stateRevision # => 1
|
||||
(pkgs.nixos [
|
||||
exampleModule
|
||||
{ system.stateVersion = "27.05"; }
|
||||
]).config.services.whatever.stateRevision # => 2
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Modules should use this function when they change how data managed by the
|
||||
module is persisted on the system between NixOS releases.
|
||||
|
||||
The default value of the option will be the number of attributes in the
|
||||
`migrations` parameter with name less than or equal to the value of
|
||||
`system.stateVersion`.
|
||||
|
||||
When using this function, don't forget to add the option's value to
|
||||
`system.moduleStateRevisions."your.module.stateRevision"` when your module is
|
||||
enabled.
|
||||
*/
|
||||
mkStateRevisionOption =
|
||||
{
|
||||
descriptionName,
|
||||
migrations,
|
||||
}:
|
||||
let
|
||||
versions = attrNames migrations;
|
||||
maxVal = length versions;
|
||||
in
|
||||
assert all (v: builtins.match "[0-9]{2}\\.[0-9]{2}" v != null) versions;
|
||||
mkOption {
|
||||
type = types.ints.between 0 maxVal;
|
||||
description = ''
|
||||
This option versions the format of state persisted by
|
||||
${descriptionName}. Its default value depends on the value of
|
||||
{option}`system.stateVersion`.
|
||||
|
||||
Users who wish to increment this option will need to take manual
|
||||
migration steps to preserve their data. **If you perform these
|
||||
migrations, rolling back to an older generation will require also
|
||||
reversing the migrations to the state expected by that generation.**
|
||||
The migrations needed to advance to each value of this option are as
|
||||
follows (perform all instructions after the row for the current
|
||||
`stateRevision`, up to and including the row for the new
|
||||
`stateRevision`):
|
||||
|
||||
0. (none)
|
||||
${concatImapStringsSep "\n" (
|
||||
v: sv: "${toString v}. ${replaceStrings [ "\n" ] [ " " ] migrations.${sv}}"
|
||||
) versions}
|
||||
|
||||
Note that you do **not** need to change {option}`system.stateVersion`
|
||||
in order to update this option. {option}`system.stateVersion` only
|
||||
determines the default value of this option. Most users should not
|
||||
change {option}`system.stateVersion` at all.
|
||||
'';
|
||||
default = findFirstIndex (versionOlder config.system.stateVersion) maxVal versions;
|
||||
defaultText = literalMD ''
|
||||
If {option}`system.stateVersion` is:
|
||||
${concatImapStringsSep "\n" (v: sv: "* <${sv}: ${toString (v - 1)}") versions}
|
||||
* otherwise: ${toString maxVal}
|
||||
'';
|
||||
}
|
||||
// {
|
||||
inherit migrations;
|
||||
};
|
||||
};
|
||||
in
|
||||
utils
|
||||
|
||||
@@ -109,10 +109,6 @@ in
|
||||
"pata_qdi"
|
||||
"pata_winbond"
|
||||
]
|
||||
++ lib.optionals (lib.versionAtLeast config.boot.kernelPackages.kernel.version "7.2") [
|
||||
# xhci-pci defers AMD 800-series chipset controllers to this driver.
|
||||
"xhci_pci_prom21"
|
||||
]
|
||||
++ lib.optionals platform.isx86 [ "vmw_balloon" ]
|
||||
++ lib.optionals (pkgs.stdenv.hostPlatform.isi686 || pkgs.stdenv.hostPlatform.isx86_64) [
|
||||
"vmw_vmci"
|
||||
|
||||
@@ -19,8 +19,8 @@ in
|
||||
[ "hardware" "logitech" "wireless" "enable" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "hardware" "logitech" "enableGraphical" ]
|
||||
[ "hardware" "logitech" "wireless" "enableGraphical" ]
|
||||
[ "programs" "solaar" "enable" ]
|
||||
)
|
||||
];
|
||||
|
||||
@@ -56,11 +56,20 @@ in
|
||||
|
||||
wireless = {
|
||||
enable = lib.mkEnableOption "support for Logitech Wireless Devices";
|
||||
|
||||
enableGraphical = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable graphical support applications.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (cfg.wireless.enable || cfg.lcd.enable) {
|
||||
environment.systemPackages = lib.optional cfg.wireless.enable pkgs.ltunify;
|
||||
environment.systemPackages =
|
||||
[ ]
|
||||
++ lib.optional cfg.wireless.enable pkgs.ltunify
|
||||
++ lib.optional cfg.wireless.enableGraphical pkgs.solaar;
|
||||
|
||||
services.udev = {
|
||||
# ltunifi and solaar both provide udev rules but the most up-to-date have been split
|
||||
|
||||
@@ -482,7 +482,7 @@ in
|
||||
combineIcdPkgs =
|
||||
icd: pkgs:
|
||||
pkgs.symlinkJoin {
|
||||
name = "nvidia-egl-external-platforms${lib.optionalString pkgs.stdenv.hostPlatform.is32bit "-x32"}";
|
||||
name = "nvidia-egl-external-platforms${lib.optionalString pkgs.stdenv.is32bit "-x32"}";
|
||||
paths = lib.attrVals icd pkgs;
|
||||
# Remediate reversed priorities in pre-595 drivers,
|
||||
# https://github.com/NixOS/nixpkgs/pull/497342#issuecomment-4034876793
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
dosfstools,
|
||||
mtools,
|
||||
e2fsprogs,
|
||||
squashfs-tools,
|
||||
squashfsTools,
|
||||
erofs-utils,
|
||||
btrfs-progs,
|
||||
xfsprogs,
|
||||
@@ -104,7 +104,7 @@ let
|
||||
mtools
|
||||
];
|
||||
"ext4" = [ e2fsprogs.bin ];
|
||||
"squashfs" = [ squashfs-tools ];
|
||||
"squashfs" = [ squashfsTools ];
|
||||
"erofs" = [ erofs-utils ];
|
||||
"btrfs" = [ btrfs-progs ];
|
||||
"xfs" = [ xfsprogs ];
|
||||
|
||||
@@ -400,7 +400,7 @@ in
|
||||
# Figure out device names for the boot device and root filesystem.
|
||||
rootPart=$(${lib.getExe' pkgs.util-linux "findmnt"} -n -o SOURCE /)
|
||||
bootDevice=$(${lib.getExe' pkgs.util-linux "lsblk"} -npo PKNAME $rootPart)
|
||||
partNum=$(${lib.getExe' pkgs.util-linux "lsblk"} -npo PARTN $rootPart)
|
||||
partNum=$(${lib.getExe' pkgs.util-linux "lsblk"} -npo MAJ:MIN $rootPart | ${lib.getExe pkgs.gawk} -F: '{print $2}')
|
||||
|
||||
# Resize the root partition and the filesystem to fit the disk
|
||||
echo ",+," | ${lib.getExe' pkgs.util-linux "sfdisk"} -N$partNum --no-reread $bootDevice
|
||||
|
||||
@@ -206,10 +206,10 @@ sub pciCheck {
|
||||
$device eq "0x4222" || $device eq "0x4227");
|
||||
|
||||
# Intel NPU driver
|
||||
# list taken from linux(v7.1): drivers/accel/ivpu/ivpu_drv.h
|
||||
# list taken from linux(v6.18): drivers/accel/ivpu/ivpu_drv.h
|
||||
if ($vendor eq "0x8086" &&
|
||||
($device eq "0x7d1d" || $device eq "0xad1d" || $device eq "0x643e" ||
|
||||
$device eq "0xb03e" || $device eq "0xfd3e" || $device eq "0xd71d"))
|
||||
($device eq "0xfd3e" || $device eq "0x7d1d" || $device eq "0xad1d" ||
|
||||
$device eq "0x643e" || $device eq "0xb03e"))
|
||||
{
|
||||
push @attrs, "hardware.cpu.intel.npu.enable = true;";
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ in
|
||||
redmine = 147;
|
||||
#seeks = 148; # removed 2020-06-21
|
||||
prosody = 149;
|
||||
# i2pd = 150; # dynamically allocated as of 2026-08-07
|
||||
i2pd = 150;
|
||||
systemd-coredump = 151;
|
||||
systemd-network = 152;
|
||||
systemd-resolve = 153;
|
||||
@@ -534,7 +534,7 @@ in
|
||||
redmine = 147;
|
||||
#seeks = 148; # removed 2020-06-21
|
||||
prosody = 149;
|
||||
# i2pd = 150; # dynamically allocated as of 2026-08-07
|
||||
i2pd = 150;
|
||||
systemd-network = 152;
|
||||
systemd-resolve = 153;
|
||||
systemd-timesync = 154;
|
||||
|
||||
@@ -254,30 +254,6 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
moduleStateRevisions = mkOption {
|
||||
type =
|
||||
let
|
||||
baseType = types.attrsOf types.ints.unsigned;
|
||||
isStateRevisionOption = x: lib.isOption x && x ? migrations;
|
||||
in
|
||||
types.addCheck baseType (
|
||||
attrs:
|
||||
builtins.all (
|
||||
attrPath: isStateRevisionOption (lib.attrByPath (lib.splitString "." attrPath) null options)
|
||||
) (builtins.attrNames attrs)
|
||||
)
|
||||
// {
|
||||
description = "${baseType.description}, in which every attribute name is the path to an option created with mkStateRevisionOption";
|
||||
};
|
||||
default = { };
|
||||
internal = true;
|
||||
description = ''
|
||||
NixOS modules should set attributes on this option. Users should leave
|
||||
it alone. Future tooling may use it to determine the consequences of
|
||||
updating {option}`system.stateVersion`.
|
||||
'';
|
||||
};
|
||||
|
||||
configurationRevision = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
|
||||
@@ -185,7 +185,6 @@
|
||||
./programs/bcc.nix
|
||||
./programs/benchexec.nix
|
||||
./programs/browserpass.nix
|
||||
./programs/btrfs-heatmap.nix
|
||||
./programs/calls.nix
|
||||
./programs/captive-browser.nix
|
||||
./programs/ccache.nix
|
||||
@@ -197,7 +196,6 @@
|
||||
./programs/cnping.nix
|
||||
./programs/comma.nix
|
||||
./programs/command-not-found/command-not-found.nix
|
||||
./programs/compsize.nix
|
||||
./programs/coolercontrol.nix
|
||||
./programs/corefreq.nix
|
||||
./programs/cpu-energy-meter.nix
|
||||
@@ -328,7 +326,6 @@
|
||||
./programs/skim.nix
|
||||
./programs/slock.nix
|
||||
./programs/sniffnet.nix
|
||||
./programs/solaar.nix
|
||||
./programs/soundmodem.nix
|
||||
./programs/ssh.nix
|
||||
./programs/starship.nix
|
||||
@@ -350,7 +347,6 @@
|
||||
./programs/tsm-client.nix
|
||||
./programs/turbovnc.nix
|
||||
./programs/udevil.nix
|
||||
./programs/upki.nix
|
||||
./programs/usbtop.nix
|
||||
./programs/vim.nix
|
||||
./programs/virt-manager.nix
|
||||
@@ -523,7 +519,6 @@
|
||||
./services/continuous-integration/buildbot/master.nix
|
||||
./services/continuous-integration/buildbot/worker.nix
|
||||
./services/continuous-integration/buildkite-agents.nix
|
||||
./services/continuous-integration/forgejo-runner.nix
|
||||
./services/continuous-integration/gitea-actions-runner.nix
|
||||
./services/continuous-integration/github-runners.nix
|
||||
./services/continuous-integration/gitlab-runner/runner.nix
|
||||
@@ -553,7 +548,6 @@
|
||||
./services/databases/hbase-standalone.nix
|
||||
./services/databases/influxdb2.nix
|
||||
./services/databases/influxdb.nix
|
||||
./services/databases/kvrocks.nix
|
||||
./services/databases/lldap.nix
|
||||
./services/databases/memcached.nix
|
||||
./services/databases/monetdb.nix
|
||||
@@ -685,7 +679,6 @@
|
||||
./services/hardware/bolt.nix
|
||||
./services/hardware/brltty.nix
|
||||
./services/hardware/buffyboard.nix
|
||||
./services/hardware/cardwired.nix
|
||||
./services/hardware/ddccontrol.nix
|
||||
./services/hardware/deepcool-digital-linux.nix
|
||||
./services/hardware/dell-bios-fan-control.nix
|
||||
@@ -1295,7 +1288,6 @@
|
||||
./services/networking/knot-resolver.nix
|
||||
./services/networking/knot.nix
|
||||
./services/networking/kresd.nix
|
||||
./services/networking/krill.nix
|
||||
./services/networking/lambdabot.nix
|
||||
./services/networking/legit.nix
|
||||
./services/networking/libreswan.nix
|
||||
@@ -1719,7 +1711,6 @@
|
||||
./services/web-apps/haven.nix
|
||||
./services/web-apps/healthchecks.nix
|
||||
./services/web-apps/hedgedoc.nix
|
||||
./services/web-apps/hister.nix
|
||||
./services/web-apps/hledger-web.nix
|
||||
./services/web-apps/homebox.nix
|
||||
./services/web-apps/homer.nix
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ sandarukasa ];
|
||||
|
||||
options = {
|
||||
programs.btrfs-heatmap = {
|
||||
enable = lib.mkEnableOption "btrfs-heatmap + setcap wrapper";
|
||||
package = lib.mkPackageOption pkgs "btrfs-heatmap" { };
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
cfg = config.programs.btrfs-heatmap;
|
||||
in
|
||||
lib.mkIf cfg.enable {
|
||||
# for the man page
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
security.wrappers.btrfs-heatmap = {
|
||||
owner = config.users.users.root.name;
|
||||
group = config.users.users.root.group;
|
||||
capabilities = "cap_sys_admin+p";
|
||||
source = lib.getExe cfg.package;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -85,32 +85,7 @@ in
|
||||
extraOpts = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
description = ''
|
||||
Extra chromium policy options. These settings are locked and the user cannot change them in the browser later.
|
||||
A list of available policies
|
||||
can be found in the Chrome Enterprise documentation:
|
||||
<https://cloud.google.com/docs/chrome-enterprise/policies/>
|
||||
Make sure the selected policy is supported on Linux and your browser version.
|
||||
'';
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"BrowserSignin" = 0;
|
||||
"SyncDisabled" = true;
|
||||
"PasswordManagerEnabled" = false;
|
||||
"SpellcheckEnabled" = true;
|
||||
"SpellcheckLanguage" = [
|
||||
"de"
|
||||
"en-US"
|
||||
];
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
extraOptsRecommended = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
description = ''
|
||||
Extra chromium policy options in recommended. These are default settings. The user can change them in the browser later if they want to.
|
||||
A list of available policies
|
||||
Extra chromium policy options. A list of available policies
|
||||
can be found in the Chrome Enterprise documentation:
|
||||
<https://cloud.google.com/docs/chrome-enterprise/policies/>
|
||||
Make sure the selected policy is supported on Linux and your browser version.
|
||||
@@ -166,9 +141,6 @@ in
|
||||
"chromium/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != { }) {
|
||||
text = builtins.toJSON cfg.extraOpts;
|
||||
};
|
||||
"chromium/policies/recommended/extra.json" = lib.mkIf (cfg.extraOptsRecommended != { }) {
|
||||
text = builtins.toJSON cfg.extraOptsRecommended;
|
||||
};
|
||||
"chromium/initial_preferences" = lib.mkIf (cfg.initialPrefs != { }) {
|
||||
text = builtins.toJSON cfg.initialPrefs;
|
||||
};
|
||||
@@ -184,9 +156,6 @@ in
|
||||
"opt/chrome/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != { }) {
|
||||
text = builtins.toJSON cfg.extraOpts;
|
||||
};
|
||||
"opt/chrome/policies/recommended/extra.json" = lib.mkIf (cfg.extraOptsRecommended != { }) {
|
||||
text = builtins.toJSON cfg.extraOptsRecommended;
|
||||
};
|
||||
# for brave
|
||||
"brave/policies/managed/default.json" = lib.mkIf (defaultProfile != { }) {
|
||||
text = builtins.toJSON defaultProfile;
|
||||
@@ -194,9 +163,6 @@ in
|
||||
"brave/policies/managed/extra.json" = lib.mkIf (cfg.extraOpts != { }) {
|
||||
text = builtins.toJSON cfg.extraOpts;
|
||||
};
|
||||
"brave/policies/recommended/extra.json" = lib.mkIf (cfg.extraOptsRecommended != { }) {
|
||||
text = builtins.toJSON cfg.extraOptsRecommended;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ sandarukasa ];
|
||||
|
||||
options = {
|
||||
programs.compsize = {
|
||||
enable = lib.mkEnableOption "compsize + setcap wrapper";
|
||||
package = lib.mkPackageOption pkgs "compsize" { };
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
cfg = config.programs.compsize;
|
||||
in
|
||||
lib.mkIf cfg.enable {
|
||||
# for the man page
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
security.wrappers.compsize = {
|
||||
owner = config.users.users.root.name;
|
||||
group = config.users.users.root.group;
|
||||
capabilities = "cap_sys_admin+p";
|
||||
source = lib.getExe cfg.package;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -92,11 +92,6 @@ in
|
||||
]
|
||||
);
|
||||
|
||||
restartTriggers = [
|
||||
cfg.package
|
||||
config.environment.etc."gamemode.ini".source
|
||||
];
|
||||
|
||||
serviceConfig.ExecStart = lib.mkIf cfg.enableRenice [
|
||||
"" # Tell systemd to clear the existing ExecStart list, to prevent appending to it.
|
||||
"${config.security.wrapperDir}/gamemoded"
|
||||
|
||||
@@ -10,11 +10,6 @@ let
|
||||
package = cfg.package.override {
|
||||
inherit (config.security) wrapperDir;
|
||||
};
|
||||
|
||||
uiPackage = cfg.ui.package.override {
|
||||
gpu-screen-recorder = package;
|
||||
inherit (config.security) wrapperDir;
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -29,47 +24,19 @@ in
|
||||
wrappers for promptless recording.
|
||||
'';
|
||||
};
|
||||
|
||||
ui = {
|
||||
enable = lib.mkEnableOption "the GPU Screen Recorder overlay UI";
|
||||
package = lib.mkPackageOption pkgs "gpu-screen-recorder-ui" { };
|
||||
notifPackage = lib.mkPackageOption pkgs "gpu-screen-recorder-notification" { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
security.wrappers."gsr-kms-server" = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
capabilities = "cap_sys_admin+ep";
|
||||
source = lib.getExe' package "gsr-kms-server";
|
||||
};
|
||||
}
|
||||
security.wrappers."gsr-kms-server" = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
capabilities = "cap_sys_admin+ep";
|
||||
source = lib.getExe' package "gsr-kms-server";
|
||||
};
|
||||
};
|
||||
|
||||
(lib.mkIf cfg.ui.enable {
|
||||
environment.systemPackages = [
|
||||
cfg.ui.package
|
||||
cfg.ui.notifPackage
|
||||
];
|
||||
|
||||
security.wrappers."gsr-global-hotkeys" = {
|
||||
owner = "root";
|
||||
group = "root";
|
||||
capabilities = "cap_setuid+ep";
|
||||
source = lib.getExe' uiPackage "gsr-global-hotkeys";
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
timschumi
|
||||
AhmedAmr
|
||||
keenanweaver
|
||||
];
|
||||
meta.maintainers = with lib.maintainers; [ timschumi ];
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.solaar;
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
types
|
||||
maintainers
|
||||
mkPackageOption
|
||||
;
|
||||
in
|
||||
{
|
||||
options.programs.solaar = {
|
||||
enable = mkEnableOption "Solaar, the open source driver for Logitech devices.";
|
||||
|
||||
package = mkPackageOption pkgs "solaar" { };
|
||||
|
||||
userService = {
|
||||
enable = mkEnableOption "Enable the solaar systemd service for each user.";
|
||||
|
||||
window = mkOption {
|
||||
type = types.enum [
|
||||
"show"
|
||||
"hide"
|
||||
"only"
|
||||
];
|
||||
default = "hide";
|
||||
description = ''
|
||||
Start with window showing / hidden / only (no tray icon).
|
||||
'';
|
||||
};
|
||||
|
||||
batteryIcons = mkOption {
|
||||
type = types.enum [
|
||||
"regular"
|
||||
"symbolic"
|
||||
"solaar"
|
||||
];
|
||||
default = "regular";
|
||||
description = ''
|
||||
Prefer regular battery / symbolic battery / solaar icons.
|
||||
'';
|
||||
};
|
||||
|
||||
extraArgs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [ "--restart-on-wake-up" ];
|
||||
description = ''
|
||||
Extra arguments to pass to Solaar.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
hardware.logitech.wireless.enable = lib.mkDefault true;
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
systemd.user.services.solaar = mkIf cfg.userService.enable {
|
||||
description = "Solaar, the open source driver for Logitech devices";
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
partOf = [ "graphical-session.target" ];
|
||||
after = [ "dbus.service" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = lib.escapeShellArgs (
|
||||
[
|
||||
(lib.getExe cfg.package)
|
||||
"--window"
|
||||
cfg.userService.window
|
||||
"--battery-icons"
|
||||
cfg.userService.batteryIcons
|
||||
]
|
||||
++ cfg.userService.extraArgs
|
||||
);
|
||||
Restart = "on-failure";
|
||||
RestartSec = "5";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = [ maintainers.Svenum ];
|
||||
};
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.upki;
|
||||
format = pkgs.formats.toml { };
|
||||
configFile = format.generate "upki.toml" cfg.settings;
|
||||
in
|
||||
{
|
||||
options.services.upki = {
|
||||
enable = lib.mkEnableOption "upki certificate infrastructure cache updates";
|
||||
|
||||
package = lib.mkPackageOption pkgs "upki" { };
|
||||
|
||||
interval = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "2h";
|
||||
example = "1h";
|
||||
description = "How often to update the upki cache.";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
inherit (format) type;
|
||||
default = { };
|
||||
description = "Settings written to the upki config file.";
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
cache-dir = "/var/cache/upki";
|
||||
revocation.fetch-url = "https://upki.rustls.dev/";
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
services.upki.settings = {
|
||||
cache-dir = lib.mkDefault "/var/cache/upki";
|
||||
revocation.fetch-url = lib.mkDefault "https://upki.rustls.dev/";
|
||||
};
|
||||
|
||||
users.users.upki = {
|
||||
isSystemUser = true;
|
||||
group = "upki";
|
||||
};
|
||||
users.groups.upki = { };
|
||||
|
||||
systemd.services.upki-fetch = {
|
||||
description = "Update the upki cache";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${lib.getExe cfg.package} --config-file ${configFile} fetch";
|
||||
User = "upki";
|
||||
Group = "upki";
|
||||
CacheDirectory = "upki";
|
||||
CacheDirectoryMode = "0755";
|
||||
UMask = "0022";
|
||||
|
||||
# Hardening
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallFilter = "@system-service";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.upki-fetch = {
|
||||
description = "Update the upki cache every ${cfg.interval}";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnActiveSec = "0";
|
||||
OnUnitActiveSec = cfg.interval;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
}:
|
||||
let
|
||||
inherit (lib.options) mkEnableOption mkPackageOption mkOption;
|
||||
inherit (lib.modules) mkIf mkAfter;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.meta) getExe;
|
||||
inherit (lib.types) listOf str;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
@@ -52,15 +52,15 @@ in
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
programs = {
|
||||
zsh.interactiveShellInit = mkIf cfg.enableZshIntegration (mkAfter ''
|
||||
zsh.interactiveShellInit = mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${getExe cfg.package} init zsh ${cfgFlags} )"
|
||||
'');
|
||||
bash.interactiveShellInit = mkIf cfg.enableBashIntegration (mkAfter ''
|
||||
'';
|
||||
bash.interactiveShellInit = mkIf cfg.enableBashIntegration ''
|
||||
eval "$(${getExe cfg.package} init bash ${cfgFlags} )"
|
||||
'');
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration (mkAfter ''
|
||||
'';
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
|
||||
${getExe cfg.package} init fish ${cfgFlags} | source
|
||||
'');
|
||||
'';
|
||||
xonsh.config = ''
|
||||
execx($(${getExe cfg.package} init xonsh ${cfgFlags}), 'exec', __xonsh__.ctx, filename='zoxide')
|
||||
'';
|
||||
|
||||
@@ -79,7 +79,7 @@ in
|
||||
};
|
||||
|
||||
firstUid = mkOption {
|
||||
type = types.ints.between 1000 65533;
|
||||
type = types.numbers.between 1000 65533;
|
||||
default = 60000;
|
||||
description = ''
|
||||
Start of block of UIDs reserved for sandboxes.
|
||||
@@ -87,7 +87,7 @@ in
|
||||
};
|
||||
|
||||
firstGid = mkOption {
|
||||
type = types.ints.between 1000 65533;
|
||||
type = types.numbers.between 1000 65533;
|
||||
default = 60000;
|
||||
description = ''
|
||||
Start of block of GIDs reserved for sandboxes.
|
||||
@@ -95,7 +95,7 @@ in
|
||||
};
|
||||
|
||||
numBoxes = mkOption {
|
||||
type = types.ints.between 1000 65533;
|
||||
type = types.numbers.between 1000 65533;
|
||||
default = 1000;
|
||||
description = ''
|
||||
Number of UIDs and GIDs to reserve, starting from
|
||||
|
||||
@@ -84,10 +84,12 @@ let
|
||||
}
|
||||
}
|
||||
'';
|
||||
__structuredAttrs = true;
|
||||
passAsFile = [
|
||||
"expectScript"
|
||||
];
|
||||
};
|
||||
checkPhase = ''
|
||||
printf "%s" "$expectScript" | ${lib.getExe pkgs.buildPackages.expect} -f -
|
||||
${lib.getExe pkgs.buildPackages.expect} -f "$expectScriptPath"
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ in
|
||||
DynamicUser = true;
|
||||
ExecStart = lib.getExe cfg.package;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
PrivateDevices = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
|
||||
@@ -1,529 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
foldlAttrs
|
||||
literalExpression
|
||||
literalMD
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
mkPackageOption
|
||||
mkRemovedOptionModule
|
||||
mkRenamedOptionModule
|
||||
nameValuePair
|
||||
optionals
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.services.forgejo-runner;
|
||||
settingsFormat = pkgs.formats.yaml { };
|
||||
config' = config;
|
||||
|
||||
# An option type for cfg.secrets that is like cfg.settings (free-form yaml), but limited
|
||||
# to just path and attrsOf path. It uses the same implementation primivites as
|
||||
# pkgs.formats.yaml (serializableValueWith).
|
||||
# The alternative would be something like types.any, which is too weak, or a hard-coded
|
||||
# max-depth by chaining multiple types.oneOf and types.attrsOf together, which is both
|
||||
# longer in code and less future-proof.
|
||||
secretsTypeBase = types.oneOf [
|
||||
types.externalPath
|
||||
(types.attrsOf secretsTypeBase)
|
||||
];
|
||||
secretsType = secretsTypeBase // {
|
||||
description = "nested attribute set of ${types.externalPath.description}";
|
||||
};
|
||||
|
||||
labels =
|
||||
instance:
|
||||
instance.settings.runner.labels
|
||||
++ (lib.flatten (
|
||||
lib.mapAttrsToList (_: value: value.labels or [ ]) instance.settings.server.connections
|
||||
));
|
||||
in
|
||||
{
|
||||
meta.maintainers = pkgs.forgejo-runner.meta.maintainers;
|
||||
|
||||
options.services.forgejo-runner = {
|
||||
package = mkPackageOption pkgs "forgejo-runner" { };
|
||||
|
||||
instances = mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
Forgejo Runner instances.
|
||||
'';
|
||||
type = types.attrsOf (
|
||||
types.submodule (
|
||||
{
|
||||
options,
|
||||
config,
|
||||
name,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [
|
||||
../../misc/assertions.nix
|
||||
|
||||
# compat for users coming from nixos/gitea-actions-runner
|
||||
(mkRenamedOptionModule [ "url" ] [ "settings" "server" "connections" "default" "url" ])
|
||||
(mkRenamedOptionModule [ "labels" ] [ "settings" "runner" "labels" ])
|
||||
(mkRemovedOptionModule [ "name" ] ''
|
||||
The option `${options.name}' has been removed, because it has no longer
|
||||
any effect, as runners no longer self-report their name to Forgejo.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "token" ] ''
|
||||
The option `${options.token}' has been renamed to
|
||||
`${options.settings}.server.connections.default.token'
|
||||
but additional attention is required.
|
||||
|
||||
Assuming you are migrating from `services.gitea-actions-runner', you will need to:
|
||||
|
||||
1. Find the old `.runner' file of your previously registered runner. You will need
|
||||
to extract two values from it. Given the instance name of "${name}", you should
|
||||
be able to find it at `/var/lib/gitea-runner/${name}/.runner'.
|
||||
|
||||
2. Read the contents of it, for example using `cat /var/lib/gitea-runner/native/.runner'.
|
||||
|
||||
3. Take note of the "uuid" and set the option `${options.settings}.server.connections.default.uuid'
|
||||
to that value. For example "c9e50be9-a7c3-4aee-ba35-624c4ff8c519".
|
||||
|
||||
4. Take note of the "token" and set the option `${options.settings}.server.connections.default.token'
|
||||
to that value. For example "6634bb58be0db23cc013a2e72dd1828ae0257cf".
|
||||
|
||||
5. Remove option `${options.token}'.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "tokenFile" ] ''
|
||||
The option `${options.tokenFile}' has been renamed to
|
||||
`${options.secrets}.server.connections.default.token_url'
|
||||
but additional attention is required.
|
||||
|
||||
Assuming you are migrating from `services.gitea-actions-runner', you will need to:
|
||||
|
||||
1. Find the old `.runner' file of your previously registered runner. You will need
|
||||
to extract two values from it. Given the instance name of "${name}", you should
|
||||
be able to find it at `/var/lib/gitea-runner/${name}/.runner'.
|
||||
|
||||
2. Read the contents of it, for example using `cat /var/lib/gitea-runner/native/.runner'.
|
||||
|
||||
3. Take note of the "uuid" and set the option `${options.settings}.server.connections.default.uuid'
|
||||
to that value. For example "c9e50be9-a7c3-4aee-ba35-624c4ff8c519".
|
||||
|
||||
4. Take note of the "token" and replace the contents of your existing token file with it.
|
||||
You no longer need to prefix the token with `TOKEN='. Put just the token in that file
|
||||
and nothing else.
|
||||
|
||||
5. Rename `${options.tokenFile}' to `${options.secrets}.server.connections.default.token_url'.
|
||||
'')
|
||||
];
|
||||
|
||||
config = mkIf config.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
lib.any (label: lib.hasInfix ":docker" label) (labels config)
|
||||
-> (
|
||||
config.runtimes.docker
|
||||
|| config.runtimes.podman
|
||||
# Mute assertion as an escape hatch for end-users
|
||||
# that override our options.runtimes default.
|
||||
|| options.runtimes.docker.highestPrio < (lib.mkOptionDefault { }).priority
|
||||
|| options.runtimes.podman.highestPrio < (lib.mkOptionDefault { }).priority
|
||||
);
|
||||
message = ''
|
||||
The option `${options.settings}' has at least one label of
|
||||
type `docker' configured, but no compatible container runtime enabled.
|
||||
|
||||
You need to enable either
|
||||
`config.virtualisation.docker.enable' or
|
||||
`config.virtualisation.podman.enable'.
|
||||
|
||||
If you are absolutely sure what you are doing
|
||||
and are certain this is wrong, you can set
|
||||
`${options.runtimes.docker}' or
|
||||
`${options.runtimes.podman}' to dismiss this assertion.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = config.settings.server.connections != { };
|
||||
message = ''
|
||||
The option `${options.settings}.server.connections' requires at least one connection.
|
||||
'';
|
||||
}
|
||||
]
|
||||
++ (foldlAttrs (
|
||||
assertions: _: connection:
|
||||
assertions ++ connection.assertions
|
||||
) [ ] config.settings.server.connections);
|
||||
};
|
||||
|
||||
options = {
|
||||
enable = mkEnableOption "this Forgejo Runner instance";
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
Free-form settings written directly to the {file}`config.yaml` file.
|
||||
Refer to [`config.example.yaml`] or run {command}`forgejo-runner generation-config` for supported values.
|
||||
|
||||
[`config.example.yaml`]: https://code.forgejo.org/forgejo/runner/src/branch/main/internal/pkg/config/config.example.yaml
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
|
||||
config = lib.mapAttrsRecursive (
|
||||
path: _: "file:$CREDENTIALS_DIRECTORY/${lib.join "__" path}"
|
||||
) config.secrets;
|
||||
|
||||
options = {
|
||||
runner = {
|
||||
labels = mkOption {
|
||||
# TODO: Support new attrset format (yaml map)
|
||||
# https://code.forgejo.org/forgejo/runner/pulls/1571
|
||||
type = types.listOf types.str;
|
||||
example = literalExpression ''
|
||||
[
|
||||
# provide a debian base with nodejs for actions
|
||||
"debian-latest:docker://node:current"
|
||||
# fake the ubuntu name, because node provides no ubuntu builds
|
||||
"ubuntu-latest:docker://node:current"
|
||||
# provide native execution on the host
|
||||
#"native:host"
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
Labels used to map jobs to their runtime environment.
|
||||
|
||||
Many common actions require {command}`bash`, {command}`git` and {command}`node`,
|
||||
as well as a filesystem that follows the filesystem hierarchy standard.
|
||||
|
||||
If you specify a label of type `docker`, the resulting runner service
|
||||
will be automatically added to the *Podman* or *Docker* group.
|
||||
|
||||
See <https://forgejo.org/docs/latest/admin/actions/configuration/#choosing-labels>.
|
||||
|
||||
::: {.note}
|
||||
Labels of type [`lxc`] are currently not supported.
|
||||
:::
|
||||
|
||||
[`lxc`]: https://forgejo.org/docs/latest/admin/actions/configuration/#lxc
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
server = {
|
||||
connections = mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
One or more connections to Forgejo instances, each with a UUID and Token pair.
|
||||
|
||||
See <https://forgejo.org/docs/latest/admin/actions/registration/>.
|
||||
|
||||
::: {.note}
|
||||
Ephemeral runner mode is not yet supported by this module.
|
||||
:::
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
default = {
|
||||
url = "https://example.com/";
|
||||
uuid = "c9e50be9-a7c3-4aee-ba35-624c4ff8c519";
|
||||
|
||||
# Also see ${options.secrets}.server.connections.<name>.token_url
|
||||
token = "6634bb58be0db23cc013a2e72dd1828ae0257cf";
|
||||
};
|
||||
}
|
||||
'';
|
||||
type = types.attrsOf (
|
||||
types.submodule (
|
||||
{ name, config, ... }:
|
||||
|
||||
{
|
||||
freeformType = settingsFormat.type;
|
||||
|
||||
imports = [
|
||||
../../misc/assertions.nix
|
||||
];
|
||||
|
||||
config = {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
(config.token == null && config ? token_url && config.token_url != null)
|
||||
|| (config.token != null && config ? token_url && config.token_url == null)
|
||||
|| (config.token != null && !config ? token_url);
|
||||
message = ''
|
||||
The option `${options.settings}' needs to have exactly one of
|
||||
`server.connections.${name}.token_url': ${
|
||||
if config ? token_url then lib.toJSON config.token_url else "<not set>"
|
||||
} or
|
||||
`server.connections.${name}.token': ${lib.toJSON config.token}
|
||||
that is *not* null.
|
||||
|
||||
Hint:
|
||||
`${options.secrets}.server.connections.${name}.token_url' will set
|
||||
`${options.settings}.server.connections.${name}.token_url' for you.
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
options = {
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
example = "https://example.com/";
|
||||
description = ''
|
||||
Base URL of your Forgejo instance.
|
||||
'';
|
||||
};
|
||||
uuid = mkOption {
|
||||
type = types.str;
|
||||
example = "c9e50be9-a7c3-4aee-ba35-624c4ff8c519";
|
||||
description = ''
|
||||
UUID of this runner.
|
||||
|
||||
See <https://forgejo.org/docs/latest/admin/actions/registration/>.
|
||||
'';
|
||||
};
|
||||
token = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
example = "6634bb58be0db23cc013a2e72dd1828ae0257cf";
|
||||
description = ''
|
||||
Token of this runner.
|
||||
|
||||
See <https://forgejo.org/docs/latest/admin/actions/registration/>.
|
||||
|
||||
::: {.note}
|
||||
The deprecated "Registration Token" is not supported.
|
||||
You need a UUID and Token pair.
|
||||
:::
|
||||
|
||||
::: {.warning}
|
||||
The value will be stored unencrypted in the world-readable Nix store.
|
||||
To store the secret securely, see {option}`${options.secrets}.server.connections.<name>.token_url`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
secrets = mkOption {
|
||||
type = secretsType;
|
||||
default = { };
|
||||
description = ''
|
||||
This follows the same structure as {option}`${options.settings}`
|
||||
but the value of each key is a path.
|
||||
|
||||
The specified secret path is then read by systemd via [`LoadCredential=`]
|
||||
and templated into {option}`${options.settings}` for you.
|
||||
|
||||
[`LoadCredential=`]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Credentials
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
server.connections.example = {
|
||||
token_url = "/run/keys/forgejo-runner_token";
|
||||
};
|
||||
|
||||
cache = {
|
||||
secret_url = "/run/keys/forgejo-runner_cache-secret";
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
hostPackages = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = with pkgs; [
|
||||
bash
|
||||
coreutils
|
||||
curl
|
||||
gawk
|
||||
gnused
|
||||
nodejs
|
||||
wget
|
||||
];
|
||||
defaultText = literalExpression ''
|
||||
with pkgs; [
|
||||
bash
|
||||
coreutils
|
||||
curl
|
||||
gawk
|
||||
gnused
|
||||
nodejs
|
||||
wget
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of packages that are available to your workflow and actions when the
|
||||
runner is configured with a label of type `host` ({option}`${options.runtimes.host}`).
|
||||
|
||||
::: {.note}
|
||||
{command}`gitMinimal` is always part of the environment because {command}`forgejo-runner`
|
||||
depends on it. If you need a different variant of {command}`git`, e.g. {command}`gitFull`,
|
||||
add it here. Your package will take priority over {command}`gitMinimal`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
runtimes = {
|
||||
host = mkOption {
|
||||
type = types.bool;
|
||||
default = lib.any (label: lib.hasSuffix ":host" label) (labels config);
|
||||
defaultText = literalMD "Whether this instance has at least one label with suffix `:host`.";
|
||||
description = ''
|
||||
Whether to configure the systemd service for jobs with the backend of type `host`.
|
||||
|
||||
::: {.warning}
|
||||
Setting this will override the automatic detection and safeguards.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
docker = mkOption {
|
||||
type = types.bool;
|
||||
default =
|
||||
lib.any (label: lib.hasInfix ":docker" label) (labels config)
|
||||
&& config'.virtualisation.docker.enable;
|
||||
defaultText = literalMD ''
|
||||
Whether this instance has at least one label with infix `:docker`
|
||||
and {option}`config.virtualisation.docker.enable` set to `true`.
|
||||
'';
|
||||
description = ''
|
||||
Whether to configure the systemd service to work with Docker.
|
||||
|
||||
::: {.warning}
|
||||
Setting this will override the automatic detection and safeguards.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
podman = mkOption {
|
||||
type = types.bool;
|
||||
default =
|
||||
lib.any (label: lib.hasInfix ":docker" label) (labels config)
|
||||
&& config'.virtualisation.podman.enable;
|
||||
defaultText = literalMD ''
|
||||
Whether this instance has at least one label with infix `:docker`
|
||||
and {option}`config.virtualisation.podman.enable` set to `true`.
|
||||
'';
|
||||
description = ''
|
||||
Whether to configure the systemd service to work with Podman.
|
||||
|
||||
::: {.warning}
|
||||
Setting this will override the automatic detection and safeguards.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
configFile = mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
type = types.path;
|
||||
default = settingsFormat.generate "config.yaml" (
|
||||
# Filter out remains of ../misc/assertions.nix.
|
||||
# Note: This is for optics only, as forgejo-runner simply ignores settings it does not know.
|
||||
lib.filterAttrsRecursive (n: _: n != "assertions" && n != "warnings") config.settings
|
||||
);
|
||||
description = ''
|
||||
Implementation detail for use in {file}`nixos/tests/forgejo.nix`.
|
||||
|
||||
FIXME: Offload into top-level config once upstream supports {var}`uuid_url`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.instances != { }) {
|
||||
assertions = (
|
||||
foldlAttrs (
|
||||
assertions: _: instance:
|
||||
assertions ++ instance.assertions
|
||||
) [ ] cfg.instances
|
||||
);
|
||||
|
||||
warnings = (
|
||||
foldlAttrs (
|
||||
warnings: _: instance:
|
||||
warnings ++ instance.warnings
|
||||
) [ ] cfg.instances
|
||||
);
|
||||
|
||||
systemd.services = lib.mapAttrs' (
|
||||
name: instance:
|
||||
nameValuePair "forgejo-runner-${utils.escapeSystemdPath name}" {
|
||||
inherit (instance) enable;
|
||||
description = "Forgejo Runner";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
]
|
||||
++ optionals instance.runtimes.docker [
|
||||
"docker.service"
|
||||
]
|
||||
++ optionals instance.runtimes.podman [
|
||||
# TODO: Add support for rootless Podman
|
||||
"podman.service"
|
||||
];
|
||||
wantedBy = [
|
||||
"multi-user.target"
|
||||
];
|
||||
environment = {
|
||||
HOME = "/var/lib/forgejo-runner/${name}";
|
||||
};
|
||||
path = optionals instance.runtimes.host instance.hostPackages ++ [ pkgs.gitMinimal ];
|
||||
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
StateDirectory = "forgejo-runner/${name}";
|
||||
WorkingDirectory = "/var/lib/forgejo-runner/${name}";
|
||||
|
||||
# DynamicUser will try to use id-mapped mounts for exec directories,
|
||||
# which has the side-effect of setting nosuid and noexec as mount option.
|
||||
# Users of host runners expect to be able to execute scripts in their
|
||||
# pipeline, so we override the noexec mount option by setting ExecPaths.
|
||||
ExecPaths = optionals instance.runtimes.host [ "/var/lib/forgejo-runner/${name}" ];
|
||||
ExecStart = toString [
|
||||
(lib.getExe cfg.package)
|
||||
"daemon"
|
||||
"--config"
|
||||
instance.configFile
|
||||
];
|
||||
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
|
||||
LoadCredential = lib.mapAttrsToListRecursive (
|
||||
path: value: "${lib.join "__" path}:${value}"
|
||||
) instance.secrets;
|
||||
|
||||
SupplementaryGroups =
|
||||
optionals instance.runtimes.docker [
|
||||
"docker"
|
||||
]
|
||||
++ optionals instance.runtimes.podman [
|
||||
"podman"
|
||||
];
|
||||
};
|
||||
}
|
||||
) cfg.instances;
|
||||
};
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
# shellcheck shell=bash
|
||||
# Request an installation access token for a GitHub App.
|
||||
#
|
||||
# Adapted from https://github.com/myoung34/docker-github-actions-runner (MIT,
|
||||
# Copyright (c) 2020 Marcus Young), see:
|
||||
# https://github.com/orgs/community/discussions/24743#discussioncomment-3245300
|
||||
#
|
||||
# Expects the following environment variables:
|
||||
# * APP_ID the GitHub App's ID
|
||||
# * APP_PRIVATE_KEY the GitHub App's PEM-encoded private key (contents)
|
||||
# * APP_LOGIN the org/user login the App is installed on
|
||||
# * GITHUB_HOST optional, defaults to github.com (set for GHES)
|
||||
#
|
||||
# Prints the installation access token (prefixed with `ghs_`) to stdout.
|
||||
|
||||
_GITHUB_HOST=${GITHUB_HOST:="github.com"}
|
||||
|
||||
# If the host is not github.com, use the GitHub Enterprise Server API endpoint.
|
||||
if [[ ${_GITHUB_HOST} == "github.com" ]]; then
|
||||
URI="https://api.${_GITHUB_HOST}"
|
||||
else
|
||||
URI="https://${_GITHUB_HOST}/api/v3"
|
||||
fi
|
||||
|
||||
API_VERSION=v3
|
||||
API_HEADER="Accept: application/vnd.github.${API_VERSION}+json"
|
||||
CONTENT_LENGTH_HEADER="Content-Length: 0"
|
||||
APP_INSTALLATIONS_URI="${URI}/app/installations"
|
||||
|
||||
# JWT token issuance and expiration parameters, see:
|
||||
# https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app
|
||||
JWT_IAT_DRIFT=60
|
||||
JWT_EXP_DELTA=600
|
||||
|
||||
JWT_JOSE_HEADER='{
|
||||
"alg": "RS256",
|
||||
"typ": "JWT"
|
||||
}'
|
||||
|
||||
build_jwt_payload() {
|
||||
now=$(date +%s)
|
||||
iat=$((now - JWT_IAT_DRIFT))
|
||||
jq -c \
|
||||
--arg iat_str "${iat}" \
|
||||
--arg exp_delta_str "${JWT_EXP_DELTA}" \
|
||||
--arg app_id_str "${APP_ID}" \
|
||||
'
|
||||
($iat_str | tonumber) as $iat
|
||||
| ($exp_delta_str | tonumber) as $exp_delta
|
||||
| ($app_id_str | tonumber) as $app_id
|
||||
| .iat = $iat
|
||||
| .exp = ($iat + $exp_delta)
|
||||
| .iss = $app_id
|
||||
' <<<"{}" | tr -d '\n'
|
||||
}
|
||||
|
||||
base64url() {
|
||||
base64 | tr '+/' '-_' | tr -d '=\n'
|
||||
}
|
||||
|
||||
rs256_sign() {
|
||||
openssl dgst -binary -sha256 -sign <(echo "$1")
|
||||
}
|
||||
|
||||
request_access_token() {
|
||||
jwt_payload=$(build_jwt_payload)
|
||||
encoded_jwt_parts=$(base64url <<<"${JWT_JOSE_HEADER}").$(base64url <<<"${jwt_payload}")
|
||||
encoded_mac=$(echo -n "${encoded_jwt_parts}" | rs256_sign "${APP_PRIVATE_KEY}" | base64url)
|
||||
generated_jwt="${encoded_jwt_parts}.${encoded_mac}"
|
||||
|
||||
auth_header="Authorization: Bearer ${generated_jwt}"
|
||||
|
||||
app_installations_response=$(
|
||||
curl -fsSX GET \
|
||||
-H "${auth_header}" \
|
||||
-H "${API_HEADER}" \
|
||||
"${APP_INSTALLATIONS_URI}"
|
||||
)
|
||||
access_token_url=$(echo "${app_installations_response}" | jq --raw-output '.[] | select (.account.login == "'"${APP_LOGIN}"'" and .app_id == '"${APP_ID}"') .access_tokens_url')
|
||||
curl -fsSX POST \
|
||||
-H "${CONTENT_LENGTH_HEADER}" \
|
||||
-H "${auth_header}" \
|
||||
-H "${API_HEADER}" \
|
||||
"${access_token_url}" |
|
||||
jq --raw-output .token
|
||||
}
|
||||
|
||||
request_access_token
|
||||
@@ -42,8 +42,7 @@
|
||||
};
|
||||
|
||||
url = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Repository to add the runner to.
|
||||
|
||||
@@ -56,16 +55,12 @@
|
||||
Otherwise, you are going to get a `404 NotFound`
|
||||
from `POST https://api.github.com/actions/runner-registration`
|
||||
in the configure script.
|
||||
|
||||
Mandatory unless `orgs` is used, in which case the URL is taken
|
||||
from each `orgs.<name>.url` instead and this option is ignored.
|
||||
'';
|
||||
example = "https://github.com/nixos/nixpkgs";
|
||||
};
|
||||
|
||||
tokenFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
The full path to a file which contains either
|
||||
|
||||
@@ -73,10 +68,6 @@
|
||||
* a classic PAT
|
||||
* or a runner registration token
|
||||
|
||||
Exactly one of `tokenFile` and `githubApp` must be set. Use
|
||||
`githubApp` to authenticate via a GitHub App installation instead
|
||||
of a token file.
|
||||
|
||||
Changing this option or the `tokenFile`’s content triggers a new runner registration.
|
||||
|
||||
We suggest using the fine-grained PATs. A runner registration token is valid
|
||||
@@ -135,71 +126,6 @@
|
||||
default = "auto";
|
||||
};
|
||||
|
||||
githubApp = lib.mkOption {
|
||||
default = null;
|
||||
description = ''
|
||||
Authenticate the runner using a GitHub App installation instead
|
||||
of a `tokenFile`. Exactly one of `tokenFile` and `githubApp` must
|
||||
be set.
|
||||
|
||||
On every start the service derives a short-lived installation
|
||||
access token from the App's private key, uses it to fetch a fresh
|
||||
runner registration token and registers the runner with it. This
|
||||
avoids storing a long-lived personal access token on the host and
|
||||
pairs well with `ephemeral` runners.
|
||||
|
||||
The App needs read and write access to the
|
||||
"self-hosted runners" administration of the organisation (or
|
||||
repository) given in `url`, and must be installed on the `login`
|
||||
below.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
id = 123456;
|
||||
login = "my-org";
|
||||
privateKeyFile = "/run/secrets/github-app.pem";
|
||||
}
|
||||
'';
|
||||
type = lib.types.nullOr (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
id = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
description = "The GitHub App's ID (the numeric `App ID`, not the client ID).";
|
||||
example = 123456;
|
||||
};
|
||||
|
||||
login = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
The organisation (or user) login the GitHub App is
|
||||
installed on. Used to look up the App installation and,
|
||||
for organisation-wide runners, as the registration scope.
|
||||
|
||||
Mandatory unless `orgs` is used, in which case the login
|
||||
is taken from each `orgs.<name>.login` instead and this
|
||||
option is ignored.
|
||||
|
||||
Changing this option triggers a new runner registration.
|
||||
'';
|
||||
example = "my-org";
|
||||
};
|
||||
|
||||
privateKeyFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
The full path to a file containing the GitHub App's
|
||||
PEM-encoded private key. The file should be deployed as a
|
||||
secret and is never copied into the Nix store.
|
||||
'';
|
||||
example = "/run/secrets/github-app.pem";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
name = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
@@ -211,107 +137,6 @@
|
||||
default = name;
|
||||
};
|
||||
|
||||
count = lib.mkOption {
|
||||
type = lib.types.ints.positive;
|
||||
default = 1;
|
||||
example = 4;
|
||||
description = ''
|
||||
Number of identical runner instances to create.
|
||||
|
||||
Without `orgs`, this fans the single entry (using the
|
||||
entry-level `url`) out into `count` runner services:
|
||||
`github-runner-<name>` for `count == 1` (unchanged) and
|
||||
`github-runner-<name>-<n>` for `count > 1`. Each instance
|
||||
registers under a distinct runner name.
|
||||
|
||||
With `orgs`, this is the default replica count for every org
|
||||
that does not set its own; see `orgs.<name>.count`.
|
||||
|
||||
Pairs well with `ephemeral`.
|
||||
'';
|
||||
};
|
||||
|
||||
orgs = lib.mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
Organisations (or repositories) to serve from this entry.
|
||||
|
||||
When set, the entry fans out into one systemd service per runner
|
||||
named `github-runner-<name>-<org>-<n>`, where `<org>` is the
|
||||
attribute name and `<n>` ranges over the per-org `count`. The
|
||||
entry-level `githubApp`/`tokenFile` is shared across every org;
|
||||
only the App `login` changes per org (defaulting to the
|
||||
attribute name), so a single GitHub App installed on multiple
|
||||
orgs serves all of them.
|
||||
|
||||
Leaving this empty (the default) keeps the single-runner
|
||||
behaviour: the entry-level `url`, `name` and auth, fanned out by
|
||||
the entry-level `count`.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
org-a.count = 12;
|
||||
org-b = {
|
||||
count = 2;
|
||||
extraLabels = [ "org-b" ];
|
||||
};
|
||||
}
|
||||
'';
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
url = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "https://github.com/${name}";
|
||||
defaultText = lib.literalExpression ''"https://github.com/''${name}"'';
|
||||
description = ''
|
||||
URL of the organisation (or repository) to connect to.
|
||||
Defaults to the GitHub URL derived from the attribute name.
|
||||
'';
|
||||
};
|
||||
|
||||
login = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
defaultText = lib.literalExpression "\${name}";
|
||||
description = ''
|
||||
GitHub login (org or user) the shared `githubApp` is
|
||||
installed on. Defaults to the attribute name. Ignored
|
||||
when authenticating via `tokenFile`.
|
||||
'';
|
||||
};
|
||||
|
||||
count = lib.mkOption {
|
||||
type = lib.types.ints.positive;
|
||||
default = config.count;
|
||||
defaultText = lib.literalMD "the entry-level `count`";
|
||||
example = 4;
|
||||
description = ''
|
||||
Number of identical runner instances to create for this
|
||||
org. Defaults to the entry-level `count`. Each gets its
|
||||
own systemd service named `github-runner-<name>-<org>-<n>`
|
||||
and registers under a distinct runner name. Pairs well
|
||||
with `ephemeral`.
|
||||
'';
|
||||
};
|
||||
|
||||
extraLabels = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = lib.literalExpression ''[ "org-a" ]'';
|
||||
description = ''
|
||||
Extra labels added, on top of the entry-level `extraLabels`,
|
||||
only to this org's runners.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
runnerGroup = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# shellcheck shell=bash
|
||||
# Fetch a self-hosted runner registration token from the GitHub API.
|
||||
#
|
||||
# Adapted from https://github.com/myoung34/docker-github-actions-runner (MIT,
|
||||
# Copyright (c) 2020 Marcus Young).
|
||||
#
|
||||
# Expects the following environment variables:
|
||||
# * ACCESS_TOKEN a token authorized to manage self-hosted runners
|
||||
# (a GitHub App installation token or a suitable PAT)
|
||||
# * RUNNER_SCOPE one of `org`, `ent` or `repo`
|
||||
# * ORG_NAME the org login (for `org` scope)
|
||||
# * ENTERPRISE_NAME the enterprise slug (for `ent` scope)
|
||||
# * REPO_URL the repository URL (for `repo` scope)
|
||||
# * GITHUB_HOST optional, defaults to github.com (set for GHES)
|
||||
#
|
||||
# Prints `{"token": ..., "full_url": ...}` to stdout.
|
||||
|
||||
_GITHUB_HOST=${GITHUB_HOST:="github.com"}
|
||||
|
||||
# If the host is not github.com, use the GitHub Enterprise Server API endpoint.
|
||||
if [[ ${_GITHUB_HOST} == "github.com" ]]; then
|
||||
URI="https://api.${_GITHUB_HOST}"
|
||||
else
|
||||
URI="https://${_GITHUB_HOST}/api/v3"
|
||||
fi
|
||||
|
||||
API_VERSION=v3
|
||||
API_HEADER="Accept: application/vnd.github.${API_VERSION}+json"
|
||||
AUTH_HEADER="Authorization: token ${ACCESS_TOKEN}"
|
||||
CONTENT_LENGTH_HEADER="Content-Length: 0"
|
||||
|
||||
case ${RUNNER_SCOPE} in
|
||||
org*)
|
||||
_FULL_URL="${URI}/orgs/${ORG_NAME}/actions/runners/registration-token"
|
||||
;;
|
||||
|
||||
ent*)
|
||||
_FULL_URL="${URI}/enterprises/${ENTERPRISE_NAME}/actions/runners/registration-token"
|
||||
;;
|
||||
|
||||
*)
|
||||
_PROTO="https://"
|
||||
_URL="${REPO_URL/${_PROTO}/}"
|
||||
_PATH="$(echo "${_URL}" | grep / | cut -d/ -f2-)"
|
||||
_ACCOUNT="$(echo "${_PATH}" | cut -d/ -f1)"
|
||||
_REPO="$(echo "${_PATH}" | cut -d/ -f2)"
|
||||
_FULL_URL="${URI}/repos/${_ACCOUNT}/${_REPO}/actions/runners/registration-token"
|
||||
;;
|
||||
esac
|
||||
|
||||
RUNNER_TOKEN="$(curl -fsSX POST \
|
||||
-H "${CONTENT_LENGTH_HEADER}" \
|
||||
-H "${AUTH_HEADER}" \
|
||||
-H "${API_HEADER}" \
|
||||
"${_FULL_URL}" |
|
||||
jq -r '.token')"
|
||||
|
||||
echo "{\"token\": \"${RUNNER_TOKEN}\", \"full_url\": \"${_FULL_URL}\"}"
|
||||
@@ -1,71 +0,0 @@
|
||||
# shellcheck shell=bash
|
||||
# Force-remove a previously registered, offline self-hosted runner via the
|
||||
# GitHub API. Used before re-registering to avoid orphaned runners piling up in
|
||||
# the GitHub Actions UI.
|
||||
#
|
||||
# Adapted from https://github.com/myoung34/docker-github-actions-runner (MIT,
|
||||
# Copyright (c) 2020 Marcus Young).
|
||||
#
|
||||
# Expects the following environment variables:
|
||||
# * ACCESS_TOKEN a token authorized to manage self-hosted runners
|
||||
# * RUNNER_NAME the name of the runner to remove
|
||||
# * RUNNER_SCOPE one of `org`, `ent` or `repo`
|
||||
# * ORG_NAME the org login (for `org` scope)
|
||||
# * ENTERPRISE_NAME the enterprise slug (for `ent` scope)
|
||||
# * REPO_URL the repository URL (for `repo` scope)
|
||||
# * GITHUB_HOST optional, defaults to github.com (set for GHES)
|
||||
|
||||
_GITHUB_HOST=${GITHUB_HOST:="github.com"}
|
||||
|
||||
# If the host is not github.com, use the GitHub Enterprise Server API endpoint.
|
||||
if [[ ${_GITHUB_HOST} == "github.com" ]]; then
|
||||
URI="https://api.${_GITHUB_HOST}"
|
||||
else
|
||||
URI="https://${_GITHUB_HOST}/api/v3"
|
||||
fi
|
||||
|
||||
API_HEADER="Accept: application/vnd.github+json"
|
||||
AUTH_HEADER="Authorization: token ${ACCESS_TOKEN}"
|
||||
CONTENT_LENGTH_HEADER="Content-Length: 0"
|
||||
|
||||
runners_url() {
|
||||
case ${RUNNER_SCOPE} in
|
||||
org*)
|
||||
echo "${URI}/orgs/${ORG_NAME}/actions/runners"
|
||||
;;
|
||||
ent*)
|
||||
echo "${URI}/enterprises/${ENTERPRISE_NAME}/actions/runners"
|
||||
;;
|
||||
*)
|
||||
_PROTO="https://"
|
||||
_URL="${REPO_URL/${_PROTO}/}"
|
||||
_PATH="$(echo "${_URL}" | grep / | cut -d/ -f2-)"
|
||||
_ACCOUNT="$(echo "${_PATH}" | cut -d/ -f1)"
|
||||
_REPO="$(echo "${_PATH}" | cut -d/ -f2)"
|
||||
echo "${URI}/repos/${_ACCOUNT}/${_REPO}/actions/runners"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_RUNNERS_URL="$(runners_url)"
|
||||
|
||||
RUNNERS="$(curl -fsSX GET \
|
||||
-H "${CONTENT_LENGTH_HEADER}" \
|
||||
-H "${AUTH_HEADER}" \
|
||||
-H "${API_HEADER}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"${_RUNNERS_URL}")"
|
||||
RUNNER_ID=$(echo "$RUNNERS" | jq -r '.runners[] | select( (.name == env.RUNNER_NAME) and (.status == "offline") ) | .id')
|
||||
|
||||
if [[ $RUNNER_ID == "" ]]; then
|
||||
echo "Runner ${RUNNER_NAME} doesn't exist or is online. Nothing to unregister."
|
||||
exit 0
|
||||
fi
|
||||
echo "${RUNNER_NAME} is still registered and offline. Forcing removal..."
|
||||
|
||||
curl -fsSX DELETE \
|
||||
-H "${CONTENT_LENGTH_HEADER}" \
|
||||
-H "${AUTH_HEADER}" \
|
||||
-H "${API_HEADER}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"${_RUNNERS_URL}/${RUNNER_ID}"
|
||||
@@ -9,22 +9,6 @@
|
||||
lib.flip lib.mapAttrsToList config.services.github-runners (
|
||||
name: cfg:
|
||||
map (lib.mkIf cfg.enable) [
|
||||
{
|
||||
assertion = (cfg.tokenFile == null) != (cfg.githubApp == null);
|
||||
message = "`services.github-runners.${name}`: Exactly one of `tokenFile` and `githubApp` must be set";
|
||||
}
|
||||
{
|
||||
assertion = cfg.orgs != { } || cfg.url != null;
|
||||
message = "`services.github-runners.${name}`: `url` must be set unless `orgs` is used";
|
||||
}
|
||||
{
|
||||
assertion = cfg.orgs != { } || cfg.githubApp == null || cfg.githubApp.login != null;
|
||||
message = "`services.github-runners.${name}`: `githubApp.login` must be set unless `orgs` is used (the login is then derived per org)";
|
||||
}
|
||||
{
|
||||
assertion = cfg.orgs != { } || cfg.count == 1 || cfg.name != null;
|
||||
message = "`services.github-runners.${name}`: `name` must not be null when `count > 1` (each replica needs a distinct registration name)";
|
||||
}
|
||||
{
|
||||
assertion = !cfg.noDefaultLabels || (cfg.extraLabels != [ ]);
|
||||
message = "`services.github-runners.${name}`: The `extraLabels` option is mandatory if `noDefaultLabels` is set";
|
||||
@@ -40,49 +24,8 @@
|
||||
config.systemd.services =
|
||||
let
|
||||
enabledRunners = lib.filterAttrs (_: cfg: cfg.enable) config.services.github-runners;
|
||||
runnerInstances = lib.concatMapAttrs (
|
||||
name: cfg:
|
||||
if cfg.orgs == { } then
|
||||
# Single org/repo (entry-level `url`), fanned out by `count`. For
|
||||
# `count == 1` the service keeps the bare `github-runner-<name>` name
|
||||
# for backwards compatibility; `count > 1` suffixes `-<n>`.
|
||||
let
|
||||
suffixes = if cfg.count == 1 then [ "" ] else map (n: "-${toString n}") (lib.range 1 cfg.count);
|
||||
in
|
||||
lib.listToAttrs (
|
||||
map (
|
||||
suffix:
|
||||
lib.nameValuePair "${name}${suffix}" (
|
||||
cfg // { name = if cfg.name == null then null else "${cfg.name}${suffix}"; }
|
||||
)
|
||||
) suffixes
|
||||
)
|
||||
else
|
||||
lib.listToAttrs (
|
||||
lib.concatLists (
|
||||
lib.flip lib.mapAttrsToList cfg.orgs (
|
||||
orgName: org:
|
||||
map (
|
||||
n:
|
||||
let
|
||||
key = "${name}-${orgName}-${toString n}";
|
||||
in
|
||||
lib.nameValuePair key (
|
||||
cfg
|
||||
// {
|
||||
url = org.url;
|
||||
name = key;
|
||||
extraLabels = cfg.extraLabels ++ org.extraLabels;
|
||||
githubApp = if cfg.githubApp == null then null else cfg.githubApp // { login = org.login; };
|
||||
}
|
||||
)
|
||||
) (lib.range 1 org.count)
|
||||
)
|
||||
)
|
||||
)
|
||||
) enabledRunners;
|
||||
in
|
||||
(lib.flip lib.mapAttrs' runnerInstances (
|
||||
(lib.flip lib.mapAttrs' enabledRunners (
|
||||
name: cfg:
|
||||
let
|
||||
svcName = "github-runner-${name}";
|
||||
@@ -98,66 +41,6 @@
|
||||
currentConfigTokenFilename = ".current-token";
|
||||
|
||||
workDir = if cfg.workDir == null then runtimeDir else cfg.workDir;
|
||||
|
||||
newConfigTokenPath = "$STATE_DIRECTORY/.new-token";
|
||||
currentConfigTokenPath = "$STATE_DIRECTORY/${currentConfigTokenFilename}";
|
||||
|
||||
# Wrapper script which expects the full path of the state, working and logs
|
||||
# directory as arguments. Overrides the respective systemd variables to provide
|
||||
# unambiguous directory names. This becomes relevant, for example, if the
|
||||
# caller overrides any of the StateDirectory=, RuntimeDirectory= or LogDirectory=
|
||||
# to contain more than one directory. This causes systemd to set the respective
|
||||
# environment variables with the path of all of the given directories, separated
|
||||
# by a colon.
|
||||
writeScript =
|
||||
scriptName: lines:
|
||||
pkgs.writeShellScript "${svcName}-${scriptName}.sh" ''
|
||||
set -euo pipefail
|
||||
|
||||
STATE_DIRECTORY="$1"
|
||||
WORK_DIRECTORY="$2"
|
||||
LOGS_DIRECTORY="$3"
|
||||
|
||||
${lines}
|
||||
'';
|
||||
|
||||
ghUrlPath = lib.removePrefix "https://github.com/" cfg.url;
|
||||
ghUrlSegments = lib.filter (s: s != "") (lib.splitString "/" ghUrlPath);
|
||||
runnerScope = if lib.length ghUrlSegments >= 2 then "repo" else "org";
|
||||
appHelper =
|
||||
helperName: scriptFile:
|
||||
pkgs.writeShellApplication {
|
||||
name = helperName;
|
||||
runtimeInputs = with pkgs; [
|
||||
jq
|
||||
curl
|
||||
openssl
|
||||
coreutils
|
||||
];
|
||||
excludeShellChecks = [
|
||||
"SC2154"
|
||||
"SC2116"
|
||||
];
|
||||
text = builtins.readFile scriptFile;
|
||||
};
|
||||
fetchAccessToken = appHelper "github-app-access-token" ./app-token.sh;
|
||||
fetchRegistrationToken = appHelper "github-runner-registration-token" ./registration-token.sh;
|
||||
removeRunner = appHelper "github-runner-remove" ./remove-runner.sh;
|
||||
appEnv = lib.optionalString (cfg.githubApp != null) ''
|
||||
export APP_ID=${toString cfg.githubApp.id}
|
||||
export APP_LOGIN=${lib.escapeShellArg cfg.githubApp.login}
|
||||
APP_PRIVATE_KEY="$(cat ${lib.escapeShellArg cfg.githubApp.privateKeyFile})"
|
||||
export APP_PRIVATE_KEY
|
||||
export RUNNER_SCOPE=${runnerScope}
|
||||
export ORG_NAME=${lib.escapeShellArg cfg.githubApp.login}
|
||||
export REPO_URL=${lib.escapeShellArg cfg.url}
|
||||
${
|
||||
if cfg.name != null then
|
||||
"export RUNNER_NAME=${lib.escapeShellArg cfg.name}"
|
||||
else
|
||||
''export RUNNER_NAME="$(uname -n)"''
|
||||
}
|
||||
'';
|
||||
in
|
||||
lib.nameValuePair svcName {
|
||||
description = "GitHub Actions runner";
|
||||
@@ -201,6 +84,24 @@
|
||||
# - Set up the directory structure by creating the necessary symlinks.
|
||||
ExecStartPre =
|
||||
let
|
||||
# Wrapper script which expects the full path of the state, working and logs
|
||||
# directory as arguments. Overrides the respective systemd variables to provide
|
||||
# unambiguous directory names. This becomes relevant, for example, if the
|
||||
# caller overrides any of the StateDirectory=, RuntimeDirectory= or LogDirectory=
|
||||
# to contain more than one directory. This causes systemd to set the respective
|
||||
# environment variables with the path of all of the given directories, separated
|
||||
# by a colon.
|
||||
writeScript =
|
||||
name: lines:
|
||||
pkgs.writeShellScript "${svcName}-${name}.sh" ''
|
||||
set -euo pipefail
|
||||
|
||||
STATE_DIRECTORY="$1"
|
||||
WORK_DIRECTORY="$2"
|
||||
LOGS_DIRECTORY="$3"
|
||||
|
||||
${lines}
|
||||
'';
|
||||
runnerRegistrationConfig = lib.getAttrs [
|
||||
"ephemeral"
|
||||
"extraLabels"
|
||||
@@ -213,6 +114,8 @@
|
||||
] cfg;
|
||||
newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
|
||||
currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
|
||||
newConfigTokenPath = "$STATE_DIRECTORY/.new-token";
|
||||
currentConfigTokenPath = "$STATE_DIRECTORY/${currentConfigTokenFilename}";
|
||||
|
||||
runnerCredFiles = [
|
||||
".credentials"
|
||||
@@ -261,23 +164,6 @@
|
||||
# Always clean workDir
|
||||
find -H "$WORK_DIRECTORY" -mindepth 1 -delete
|
||||
'';
|
||||
unconfigureRunnerGitHubApp = writeScript "unconfigure-github-app" ''
|
||||
${appEnv}
|
||||
ACCESS_TOKEN="$(${lib.getExe' fetchAccessToken "github-app-access-token"})"
|
||||
export ACCESS_TOKEN
|
||||
|
||||
${lib.getExe' removeRunner "github-runner-remove"} || true
|
||||
|
||||
find "$STATE_DIRECTORY/" -mindepth 1 -delete
|
||||
|
||||
umask 000
|
||||
${lib.getExe' fetchRegistrationToken "github-runner-registration-token"} \
|
||||
| ${pkgs.jq}/bin/jq -r '.token' > "${newConfigTokenPath}"
|
||||
install --mode=600 "${newConfigTokenPath}" "${currentConfigTokenPath}"
|
||||
|
||||
# Always clean workDir
|
||||
find -H "$WORK_DIRECTORY" -mindepth 1 -delete
|
||||
'';
|
||||
configureRunner =
|
||||
writeScript "configure" # bash
|
||||
''
|
||||
@@ -299,33 +185,24 @@
|
||||
${lib.optionalString cfg.noDefaultLabels "--no-default-labels"}
|
||||
)
|
||||
token=$(<"${newConfigTokenPath}")
|
||||
${
|
||||
if cfg.githubApp != null then
|
||||
''
|
||||
args+=(--token "$token")
|
||||
''
|
||||
case ${cfg.tokenType} in
|
||||
access)
|
||||
args+=(--pat "$token")
|
||||
;;
|
||||
registration)
|
||||
args+=(--token "$token")
|
||||
;;
|
||||
auto)
|
||||
# If the token file contains a PAT (i.e., it starts with "ghp_" or "github_pat_"),
|
||||
# we have to use the --pat option, if it is not a PAT, we assume it contains a
|
||||
# registration token and use the --token option
|
||||
if [[ "$token" =~ ^gh[a-z]+_* ]] || [[ "$token" =~ ^github_pat_* ]]; then
|
||||
args+=(--pat "$token")
|
||||
else
|
||||
''
|
||||
case ${cfg.tokenType} in
|
||||
access)
|
||||
args+=(--pat "$token")
|
||||
;;
|
||||
registration)
|
||||
args+=(--token "$token")
|
||||
;;
|
||||
auto)
|
||||
# If the token file contains a PAT (i.e., it starts with "ghp_" or "github_pat_"),
|
||||
# we have to use the --pat option, if it is not a PAT, we assume it contains a
|
||||
# registration token and use the --token option
|
||||
if [[ "$token" =~ ^gh[a-z]+_* ]] || [[ "$token" =~ ^github_pat_* ]]; then
|
||||
args+=(--pat "$token")
|
||||
else
|
||||
args+=(--token "$token")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
''
|
||||
}
|
||||
args+=(--token "$token")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
${cfg.package}/bin/Runner.Listener configure "''${args[@]}"
|
||||
# Move the automatically created _diag dir to the logs dir
|
||||
mkdir -p "$STATE_DIRECTORY/_diag"
|
||||
@@ -357,33 +234,11 @@
|
||||
}"
|
||||
)
|
||||
[
|
||||
# runs as root
|
||||
"+${if cfg.githubApp != null then unconfigureRunnerGitHubApp else unconfigureRunner}"
|
||||
"+${unconfigureRunner}" # runs as root
|
||||
configureRunner
|
||||
setupWorkDir
|
||||
];
|
||||
|
||||
ExecStopPost = lib.optionals (cfg.githubApp != null) (
|
||||
let
|
||||
unregister = writeScript "unregister-github-app" ''
|
||||
${appEnv}
|
||||
ACCESS_TOKEN="$(${lib.getExe' fetchAccessToken "github-app-access-token"})"
|
||||
export ACCESS_TOKEN
|
||||
${lib.getExe' removeRunner "github-runner-remove"} || true
|
||||
'';
|
||||
in
|
||||
map (
|
||||
x:
|
||||
"${x} ${
|
||||
lib.escapeShellArgs [
|
||||
stateDir
|
||||
workDir
|
||||
logsDir
|
||||
]
|
||||
}"
|
||||
) [ "-+${unregister}" ] # runs as root
|
||||
);
|
||||
|
||||
# If running in ephemeral mode, restart the service on-exit (i.e., successful de-registration of the runner)
|
||||
# to trigger a fresh registration.
|
||||
Restart = if cfg.ephemeral then "on-success" else "no";
|
||||
@@ -401,12 +256,11 @@
|
||||
WorkingDirectory = workDir;
|
||||
|
||||
InaccessiblePaths = [
|
||||
# Token file path given in the configuration, if visible to the service
|
||||
"-${cfg.tokenFile}"
|
||||
# Token file in the state directory
|
||||
"${stateDir}/${currentConfigTokenFilename}"
|
||||
]
|
||||
# Token file path given in the configuration, if visible to the service
|
||||
++ lib.optional (cfg.tokenFile != null) "-${cfg.tokenFile}"
|
||||
++ lib.optional (cfg.githubApp != null) "-${cfg.githubApp.privateKeyFile}";
|
||||
];
|
||||
|
||||
KillSignal = "SIGINT";
|
||||
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.kvrocks;
|
||||
|
||||
format = pkgs.formats.keyValue {
|
||||
# Emit list values as repeated keys (e.g. rename-command), matching MultiStringField.
|
||||
listsAsDuplicateKeys = true;
|
||||
mkKeyValue = lib.generators.mkKeyValueDefault {
|
||||
mkValueString = v: if lib.isBool v then lib.boolToYesNo v else toString v;
|
||||
} " ";
|
||||
};
|
||||
|
||||
defaultDir = "/var/lib/kvrocks";
|
||||
dataDir = cfg.settings.dir;
|
||||
isDefaultDir = dataDir == defaultDir;
|
||||
|
||||
# Defaults match upstream Config field defaults (config.cc).
|
||||
# freeformType uses listsAsDuplicateKeys, so set values are singleton lists.
|
||||
workers = lib.head (cfg.settings.workers or [ 8 ]);
|
||||
maxBackgroundJobs = lib.head (cfg.settings."rocksdb.max_background_jobs" or [ 4 ]);
|
||||
maxclients = lib.head (cfg.settings.maxclients or [ 10240 ]);
|
||||
maxOpenFiles = lib.head (cfg.settings."rocksdb.max_open_files" or [ 8096 ]);
|
||||
|
||||
# Thread inventory from server.cc ("Kvrocks threads list") + Server::Start:
|
||||
# always-on: main, workers, task-runner (1), server-cron, compact-check,
|
||||
# rocksdb background (bounded by max_background_jobs)
|
||||
# optional: master-repl (+ ≤4 parallel fetch via std::async on full sync),
|
||||
# feed-slave per replica, slot-migrate (cluster)
|
||||
alwaysOnThreads = 1 + workers + 1 + 1 + 1 + maxBackgroundJobs;
|
||||
# 1 master-repl + 4 fetch + 1 slot-migrate + ~16 replicas + misc (jemalloc, …)
|
||||
dynamicThreadMargin = 32;
|
||||
|
||||
# From Server::AdjustOpenFilesLimit:
|
||||
# max_files = maxclients + rocksdb.max_open_files + min_reserved_fds
|
||||
# min_reserved_fds = 128 (listen sockets, logs, persistence, misc)
|
||||
openFilesReserved = 128;
|
||||
|
||||
hasUnixSocket = cfg.settings.unixsocket != "";
|
||||
hasTcp = lib.length cfg.settings.bind > 0;
|
||||
configFile = format.generate "kvrocks.conf" (
|
||||
{
|
||||
daemonize = "no";
|
||||
supervised = "systemd";
|
||||
}
|
||||
// (builtins.removeAttrs cfg.settings [
|
||||
"bind"
|
||||
"unixsocket"
|
||||
])
|
||||
// lib.optionalAttrs (hasTcp && !cfg.socketActivation) {
|
||||
bind = lib.concatStringsSep " " cfg.settings.bind;
|
||||
}
|
||||
// lib.optionalAttrs hasUnixSocket {
|
||||
unixsocket = cfg.settings.unixsocket;
|
||||
}
|
||||
// lib.optionalAttrs cfg.socketActivation {
|
||||
socket-fd = 3;
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
meta.maintainers = pkgs.kvrocks.meta.maintainers;
|
||||
|
||||
options = {
|
||||
services.kvrocks = {
|
||||
enable = lib.mkEnableOption "the Kvrocks server";
|
||||
|
||||
package = lib.mkPackageOption pkgs "kvrocks" { };
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "kvrocks";
|
||||
description = "User account under which Kvrocks runs.";
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "kvrocks";
|
||||
description = "Group under which Kvrocks runs.";
|
||||
};
|
||||
|
||||
socketActivation = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable systemd socket activation for TCP.
|
||||
Requires exactly one address in {option}`services.kvrocks.settings.bind`.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = format.type;
|
||||
|
||||
options = {
|
||||
bind = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [
|
||||
"127.0.0.1"
|
||||
"::1"
|
||||
];
|
||||
description = "The addresses to bind to.";
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 6666;
|
||||
description = "Accept connections on the specified port.";
|
||||
};
|
||||
|
||||
unixsocket = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
example = "/run/kvrocks/kvrocks.sock";
|
||||
description = "Unix socket path.";
|
||||
};
|
||||
|
||||
dir = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = defaultDir;
|
||||
description = "Directory for database files.";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
example = {
|
||||
workers = 8;
|
||||
maxclients = 10000;
|
||||
rename-command = [
|
||||
"KEYS \"\""
|
||||
"FLUSHDB \"\""
|
||||
];
|
||||
};
|
||||
description = ''
|
||||
Configuration for kvrocks.
|
||||
See <https://github.com/apache/kvrocks/blob/unstable/kvrocks.conf> for supported options.
|
||||
|
||||
List values are emitted as repeated keys (for example `rename-command`),
|
||||
except {option}`services.kvrocks.settings.bind` which is space-separated
|
||||
on a single line.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Whether to open the firewall for the kvrocks port.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = hasTcp || hasUnixSocket;
|
||||
message = "services.kvrocks: set settings.bind and/or settings.unixsocket.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.socketActivation -> builtins.length cfg.settings.bind == 1;
|
||||
message = "services.kvrocks.socketActivation requires exactly one settings.bind address.";
|
||||
}
|
||||
];
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.mkIf (cfg.openFirewall && hasTcp) [
|
||||
cfg.settings.port
|
||||
];
|
||||
|
||||
systemd.tmpfiles.settings."10-kvrocks" = lib.mkIf (!isDefaultDir) {
|
||||
${dataDir}.d = {
|
||||
user = cfg.user;
|
||||
group = cfg.group;
|
||||
mode = "0700";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.sockets.kvrocks = lib.mkIf cfg.socketActivation {
|
||||
description = "Kvrocks socket";
|
||||
wantedBy = [ "sockets.target" ];
|
||||
listenStreams =
|
||||
let
|
||||
addr = builtins.head cfg.settings.bind;
|
||||
port = toString cfg.settings.port;
|
||||
listenStream = if lib.hasInfix ":" addr then "[${addr}]:${port}" else "${addr}:${port}";
|
||||
in
|
||||
lib.singleton listenStream;
|
||||
socketConfig = {
|
||||
Accept = false;
|
||||
SocketUser = cfg.user;
|
||||
SocketGroup = cfg.group;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.kvrocks = {
|
||||
description = "Kvrocks - Distributed key value database";
|
||||
documentation = [ "https://kvrocks.apache.org/" ];
|
||||
wantedBy = lib.mkIf (!cfg.socketActivation) [ "multi-user.target" ];
|
||||
after = [ "network.target" ] ++ lib.optionals cfg.socketActivation [ "kvrocks.socket" ];
|
||||
requires = lib.optionals cfg.socketActivation [ "kvrocks.socket" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
ExecStart = "${lib.getExe cfg.package} -c ${configFile}";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
StateDirectory = lib.mkIf isDefaultDir "kvrocks";
|
||||
StateDirectoryMode = "0700";
|
||||
RuntimeDirectory = "kvrocks";
|
||||
RuntimeDirectoryMode = "0755";
|
||||
BindPaths = lib.mkIf (!isDefaultDir) [ dataDir ];
|
||||
LimitNPROC = lib.mkDefault (alwaysOnThreads + dynamicThreadMargin);
|
||||
# When rocksdb.max_open_files is -1 (unlimited), fall back to a high limit.
|
||||
LimitNOFILE = lib.mkDefault (
|
||||
if maxOpenFiles < 0 then 1048576 else maxclients + maxOpenFiles + openFilesReserved
|
||||
);
|
||||
TimeoutSec = 300;
|
||||
NonBlocking = lib.mkIf cfg.socketActivation true;
|
||||
# Capabilities
|
||||
CapabilityBoundingSet = "";
|
||||
# Security
|
||||
NoNewPrivileges = true;
|
||||
# Sandboxing
|
||||
TemporaryFileSystem = [ "/:ro" ];
|
||||
BindReadOnlyPaths = [
|
||||
builtins.storeDir
|
||||
"/etc"
|
||||
];
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
PrivateUsers = true;
|
||||
ProtectClock = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
PrivateMounts = true;
|
||||
SocketBindDeny = [ "any" ];
|
||||
SocketBindAllow = lib.optionals (hasTcp && !cfg.socketActivation) [
|
||||
"tcp:${toString cfg.settings.port}"
|
||||
];
|
||||
# System Call Filtering
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users = lib.mkIf (cfg.user == "kvrocks") {
|
||||
kvrocks = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
description = "Kvrocks daemon user";
|
||||
};
|
||||
};
|
||||
groups = lib.mkIf (cfg.group == "kvrocks") {
|
||||
kvrocks = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -752,7 +752,7 @@ in
|
||||
"AF_INET6"
|
||||
];
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
PrivateMounts = true;
|
||||
|
||||
@@ -400,15 +400,6 @@ in
|
||||
pkgs.xdg-user-dirs-gtk # Used to create the default bookmarks
|
||||
];
|
||||
|
||||
# Restarting this unit terminates the active GNOME session.
|
||||
systemd.user.services.gnome-session-monitor = {
|
||||
restartIfChanged = false;
|
||||
overrideStrategy = "asDropin";
|
||||
# No need to add the NixOS default Environment="Path=coreutils:...",
|
||||
# to the gnome-session-monitor service.
|
||||
enableDefaultPath = false;
|
||||
};
|
||||
|
||||
services.udev.packages = [
|
||||
# Force enable KMS modifiers for devices that require them.
|
||||
# https://gitlab.gnome.org/GNOME/pkgs.mutter/-/merge_requests/1443
|
||||
|
||||
@@ -22,9 +22,6 @@ let
|
||||
// lib.optionalAttrs (cfg.ipcPasswordFile != null) {
|
||||
IPCPassword = "#ipcPassword#";
|
||||
}
|
||||
// lib.optionalAttrs (cfg.licenseFile != null) {
|
||||
LicenseID = "#licenseID#";
|
||||
}
|
||||
);
|
||||
|
||||
ipc-config = format.generate "IPC.config" cfg.ipcSettings;
|
||||
@@ -112,12 +109,6 @@ in
|
||||
default = { };
|
||||
};
|
||||
|
||||
licenseFile = lib.mkOption {
|
||||
type = with lib.types; nullOr path;
|
||||
default = null;
|
||||
description = "Path to a file containing the license. The file must be readable by the `archisteamfarm` user/group.";
|
||||
};
|
||||
|
||||
ipcPasswordFile = lib.mkOption {
|
||||
type = with lib.types; nullOr path;
|
||||
default = null;
|
||||
@@ -282,10 +273,6 @@ in
|
||||
|
||||
cp --no-preserve=mode ${configFile} config/ASF.json
|
||||
|
||||
${lib.optionalString (cfg.licenseFile != null) ''
|
||||
${replaceSecretBin} '#licenseID#' '${cfg.licenseFile}' config/ASF.json
|
||||
''}
|
||||
|
||||
${lib.optionalString (cfg.ipcPasswordFile != null) ''
|
||||
${replaceSecretBin} '#ipcPassword#' '${cfg.ipcPasswordFile}' config/ASF.json
|
||||
''}
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
types
|
||||
mkPackageOption
|
||||
getExe'
|
||||
;
|
||||
cfg = config.services.cardwired;
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
in
|
||||
{
|
||||
options.services.cardwired = {
|
||||
enable = mkEnableOption "Cardwire eBPF-based GPU manager daemon";
|
||||
|
||||
package = mkPackageOption pkgs "cardwire" { };
|
||||
|
||||
settings = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
auto_apply_gpu_state = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Automatically restore GPU states on manual mode.
|
||||
'';
|
||||
};
|
||||
experimental_nvidia_block = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable blocking specifics Nvidia files. This setting is experimental
|
||||
because these files can be shared across multiple Nvidia GPUs.
|
||||
'';
|
||||
};
|
||||
battery_auto_switch = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Automatically switch mode on AC power.
|
||||
'';
|
||||
};
|
||||
battery_auto_switch_mode = mkOption {
|
||||
type = types.enum [
|
||||
"integrated"
|
||||
"hybrid"
|
||||
"manual"
|
||||
"smart"
|
||||
];
|
||||
default = "hybrid";
|
||||
description = ''
|
||||
The mode cardwire switches on AC power.
|
||||
'';
|
||||
};
|
||||
external_display_auto_switch = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Automatically make GPUs available for displays connected to dGPU-only ports.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
Configuration for {file}`/etc/cardwire.toml`
|
||||
See <https://opengamingcollective.github.io/cardwire/getting-started/usage>
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.etc."cardwire/cardwire.toml".source = tomlFormat.generate "cardwire.toml" cfg.settings;
|
||||
|
||||
services.dbus.enable = true;
|
||||
services.dbus.packages = [ cfg.package ];
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
systemd.services.cardwired = {
|
||||
description = "Cardwire Daemon";
|
||||
|
||||
restartTriggers = [ config.environment.etc."cardwire/cardwire.toml".source ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "dbus";
|
||||
BusName = "org.opengamingcollective.cardwire";
|
||||
ExecStart = getExe' cfg.package "cardwired";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "5s";
|
||||
User = "root";
|
||||
PrivateNetwork = true;
|
||||
PrivateTmp = true;
|
||||
ProtectHostname = true;
|
||||
NoNewPrivileges = true;
|
||||
ProtectClock = true;
|
||||
ProtectSystem = "strict";
|
||||
StateDirectory = "cardwire";
|
||||
StateDirectoryMode = "0700";
|
||||
ConfigurationDirectory = "cardwire";
|
||||
ConfigurationDirectoryMode = "0700";
|
||||
ProtectHome = "read-only";
|
||||
ProtectKernelLogs = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelModules = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_NETLINK"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
LockPersonality = true;
|
||||
UMask = "0077";
|
||||
IPAddressDeny = "any";
|
||||
CapabilityBoundingSet = [
|
||||
"CAP_SYS_ADMIN"
|
||||
"CAP_BPF"
|
||||
"CAP_SYS_PTRACE"
|
||||
"CAP_DAC_OVERRIDE"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -31,11 +31,8 @@ let
|
||||
originalEtc =
|
||||
let
|
||||
mkEtcFile = n: lib.nameValuePair n { source = "${cfg.package}/etc/${n}"; };
|
||||
etcFiles = lib.filter (
|
||||
f: config.boot.loader.grub.enable || f != "grub.d/35_fwupd"
|
||||
) cfg.package.filesInstalledToEtc;
|
||||
in
|
||||
lib.listToAttrs (map mkEtcFile etcFiles);
|
||||
lib.listToAttrs (map mkEtcFile cfg.package.filesInstalledToEtc);
|
||||
extraTrustedKeys =
|
||||
let
|
||||
mkName = p: "pki/fwupd/${baseNameOf p}";
|
||||
@@ -187,7 +184,7 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Disable test related plug-ins implicitly so that users do not have to care about them.
|
||||
services.fwupd.daemonSettings = {
|
||||
EspLocation = lib.mkDefault config.boot.loader.efi.efiSysMountPoint;
|
||||
EspLocation = config.boot.loader.efi.efiSysMountPoint;
|
||||
};
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
@@ -205,12 +202,6 @@ in
|
||||
systemd = {
|
||||
packages = [ cfg.package ];
|
||||
|
||||
# fwupd looks for its EFI app in /run/fwupd-efi so that signed variants can
|
||||
# be placed next to it; `C+` keeps those signed files across a rebuild.
|
||||
tmpfiles.rules = [
|
||||
"C+ /run/fwupd-efi - - - - ${cfg.package.fwupd-efi}/libexec/fwupd/efi"
|
||||
];
|
||||
|
||||
# The upstream unit runs as User=fwupd-refresh; ensure it can take
|
||||
# ownership of /var/lib/fwupd.
|
||||
services.fwupd-refresh.serviceConfig = {
|
||||
|
||||
@@ -181,9 +181,6 @@ in
|
||||
# ot-ctl can be used to query the router instance
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
# Shared by the agent and web interface for the OpenThread control socket.
|
||||
users.groups.otbr = { };
|
||||
|
||||
# Make sure we have ipv6 support, and that forwarding is enabled
|
||||
networking.enableIPv6 = true;
|
||||
networking.firewall.allowedTCPPorts =
|
||||
@@ -220,7 +217,6 @@ in
|
||||
THREAD_IF = cfg.interfaceName;
|
||||
};
|
||||
serviceConfig = {
|
||||
Group = "otbr";
|
||||
ExecStartPre = "${utils.escapeSystemdExecArg (lib.getExe' cfg.package "otbr-firewall")} start";
|
||||
ExecStart = lib.concatStringsSep " " (
|
||||
lib.concatLists [
|
||||
@@ -273,7 +269,7 @@ in
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
UMask = "0007";
|
||||
UMask = "0077";
|
||||
|
||||
CapabilityBoundingSet = [
|
||||
"CAP_NET_ADMIN"
|
||||
@@ -292,7 +288,6 @@ in
|
||||
after = [ "otbr-agent.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Group = "otbr";
|
||||
ExecStart = lib.concatStringsSep " " (
|
||||
lib.concatLists [
|
||||
[
|
||||
|
||||
@@ -10,8 +10,6 @@ let
|
||||
cfg = config.services.wyoming.faster-whisper;
|
||||
|
||||
inherit (lib)
|
||||
any
|
||||
hasInfix
|
||||
mapAttrsToList
|
||||
mkOption
|
||||
mkEnableOption
|
||||
@@ -71,7 +69,6 @@ in
|
||||
"auto"
|
||||
"faster-whisper"
|
||||
"onnx-asr"
|
||||
"qwen3-asr"
|
||||
"sherpa"
|
||||
"transformers"
|
||||
];
|
||||
@@ -314,13 +311,8 @@ in
|
||||
in
|
||||
mkIf (cfg.servers != { }) {
|
||||
assertions = mapAttrsToList (server: options: {
|
||||
assertion =
|
||||
!lib.elem options.sttLibrary [
|
||||
"faster-whisper"
|
||||
"qwen3-asr"
|
||||
]
|
||||
-> options.initialPrompt == null;
|
||||
message = "wyoming-faster-whisper/${server}: Initial prompt is only supported when `sttLibrary` is `faster-whisper` or `qwen3-asr`.";
|
||||
assertion = options.sttLibrary != "faster-whisper" -> options.initialPrompt == null;
|
||||
message = "wyoming-faster-whisper/${server}: Initial prompt is only supported when using `faster-whisper` as `sttLibrary`.";
|
||||
}) cfg.servers;
|
||||
|
||||
systemd.services = mapAttrs' (
|
||||
@@ -329,9 +321,6 @@ in
|
||||
finalPackage = cfg.package.overridePythonAttrs (oldAttrs: {
|
||||
dependencies =
|
||||
oldAttrs.dependencies
|
||||
++ optionals (any (
|
||||
arg: hasInfix "--hass" arg
|
||||
) options.extraArgs) oldAttrs.optional-dependencies.hass
|
||||
++ optionals options.zeroconf.enable oldAttrs.optional-dependencies.zeroconf
|
||||
++ optionals (
|
||||
options.sttLibrary == "onnx-asr" || options.sttLibrary == "auto" && options.language == "ru"
|
||||
|
||||
@@ -355,7 +355,7 @@ in
|
||||
PrivateDevices = true;
|
||||
ProtectSystem = "full";
|
||||
CapabilityBoundingSet = [ "~CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_BOOT CAP_SYS_MODULE" ];
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectControlGroups = true;
|
||||
|
||||
@@ -1061,7 +1061,7 @@ in
|
||||
"CAP_SYS_RESOURCE"
|
||||
];
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = false; # e.g for sendmail
|
||||
OOMPolicy = "continue";
|
||||
PrivateTmp = true;
|
||||
|
||||
@@ -1011,7 +1011,7 @@ in
|
||||
PrivateDevices = true;
|
||||
ProtectSystem = "full";
|
||||
CapabilityBoundingSet = [ "~CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_BOOT CAP_SYS_MODULE" ];
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectControlGroups = true;
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
}:
|
||||
let
|
||||
cfg = config.services.comfyui;
|
||||
|
||||
# By default a StateDirectory is used; anything else needs its own directory and a hole in the unit's mount namespace.
|
||||
isDefaultDataDir = cfg.dataDir == "/var/lib/comfyui";
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -16,20 +13,6 @@ in
|
||||
enable = lib.mkEnableOption "ComfyUI";
|
||||
package = lib.mkPackageOption pkgs "comfyui" { };
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/var/lib/comfyui";
|
||||
example = "/srv/comfyui";
|
||||
description = ''
|
||||
Directory holding ComfyUI's state: models, custom nodes, inputs, outputs and the database.
|
||||
|
||||
Defaults to the unit's `StateDirectory`.
|
||||
Any other directory is created with systemd-tmpfiles and bind-mounted into the service.
|
||||
|
||||
Existing state is not migrated, you need to move it yourself.
|
||||
'';
|
||||
};
|
||||
|
||||
listen = lib.mkOption {
|
||||
type = with lib.types; listOf str;
|
||||
default = [
|
||||
@@ -63,30 +46,19 @@ in
|
||||
];
|
||||
description = ''
|
||||
Extra arguments to pass to the server. See `comfyui --help` for available args.
|
||||
|
||||
Flags set by the module are prepended with `lib.mkBefore`, so any user supplied flag wins over that.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.comfyui.extraArgs = lib.mkBefore [
|
||||
"--base-directory=${cfg.dataDir}"
|
||||
"--database-url=sqlite:///${cfg.dataDir}/user/comfyui.db"
|
||||
services.comfyui.extraArgs = [
|
||||
"--base-directory=/var/lib/comfyui"
|
||||
"--database-url=sqlite:////var/lib/comfyui/user/comfyui.db"
|
||||
"--listen=${lib.concatStringsSep "," cfg.listen}"
|
||||
"--port=${toString cfg.port}"
|
||||
];
|
||||
|
||||
# owner read back from the unit, not spelled out: StateDirectory= infers it, this rule has to be told
|
||||
systemd.tmpfiles.settings = lib.mkIf (!isDefaultDataDir) {
|
||||
"10-comfyui".${cfg.dataDir}.d = {
|
||||
user = config.systemd.services.comfyui.serviceConfig.User;
|
||||
group = config.systemd.services.comfyui.serviceConfig.Group;
|
||||
mode = "0700";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.comfyui = {
|
||||
description = "Powerful and modular diffusion model GUI, api and backend";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
@@ -94,8 +66,8 @@ in
|
||||
|
||||
preStart = ''
|
||||
for d in custom_nodes input output models; do
|
||||
if [[ ! -d "${cfg.dataDir}/$d" ]]; then
|
||||
cp --no-preserve=all -r ${cfg.package}/share/comfyui/$d "${cfg.dataDir}/"
|
||||
if [[ ! -d /var/lib/comfyui/$d ]]; then
|
||||
cp --no-preserve=all -r ${cfg.package}/share/comfyui/$d /var/lib/comfyui/
|
||||
fi
|
||||
done
|
||||
'';
|
||||
@@ -105,13 +77,10 @@ in
|
||||
Group = "comfyui";
|
||||
Restart = "always";
|
||||
RestartSec = "5sec"; # don't crash loop immediately
|
||||
StateDirectory = lib.mkIf isDefaultDataDir "comfyui";
|
||||
StateDirectory = "comfyui";
|
||||
Type = "simple";
|
||||
User = "comfyui";
|
||||
|
||||
# This is a bind mount, not ReadWritePaths, so that with ProtectHome it is not shadowed by a tmpfs.
|
||||
BindPaths = lib.mkIf (!isDefaultDataDir) [ cfg.dataDir ];
|
||||
|
||||
# required for Torch and GPU acceleration
|
||||
BindReadOnlyPaths = [ "/proc/cpuinfo" ];
|
||||
PrivateDevices = false;
|
||||
@@ -154,7 +123,7 @@ in
|
||||
groups.comfyui = { };
|
||||
users.comfyui = {
|
||||
group = "comfyui";
|
||||
home = cfg.dataDir;
|
||||
home = "/var/lib/comfyui";
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -777,7 +777,7 @@ in
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
|
||||
@@ -953,7 +953,7 @@ in
|
||||
++ lib.optional (useSendmail && config.services.postfix.enable) "AF_NETLINK";
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
|
||||
@@ -1208,8 +1208,6 @@ in
|
||||
services.postgresql = optionalAttrs databaseActuallyCreateLocally {
|
||||
enable = true;
|
||||
ensureUsers = singleton { name = cfg.databaseUsername; };
|
||||
# With the PostgreSQL update to 17.6, the default was no longer enough.
|
||||
settings.max_locks_per_transaction = lib.mkDefault 128;
|
||||
};
|
||||
|
||||
# Enable rotation of log files
|
||||
@@ -1307,7 +1305,6 @@ in
|
||||
"d ${cfg.statePath}/custom_hooks/post-receive.d 0700 ${cfg.user} ${cfg.group} -"
|
||||
"d ${cfg.statePath}/custom_hooks/update.d 0700 ${cfg.user} ${cfg.group} -"
|
||||
"d ${gitlabConfig.production.shared.path} 0750 ${cfg.user} ${cfg.group} -"
|
||||
"d ${gitlabConfig.production.shared.path}/agent_plan_content 0750 ${cfg.user} ${cfg.group} -"
|
||||
"d ${gitlabConfig.production.shared.path}/artifacts 0750 ${cfg.user} ${cfg.group} -"
|
||||
"d ${gitlabConfig.production.shared.path}/lfs-objects 0750 ${cfg.user} ${cfg.group} -"
|
||||
"d ${gitlabConfig.production.shared.path}/packages 0750 ${cfg.user} ${cfg.group} -"
|
||||
|
||||
@@ -70,9 +70,7 @@ let
|
||||
if [[ "$USER" != ${cfg.user} ]]; then
|
||||
${
|
||||
if config.security.sudo.enable then
|
||||
"sudo='exec ${config.security.wrapperDir}/sudo -u ${cfg.user} -g ${cfg.group} ${
|
||||
lib.optionalString enableRedis " -g " + redisServer.group
|
||||
} -E'"
|
||||
"sudo='exec ${config.security.wrapperDir}/sudo -u ${cfg.user} -E'"
|
||||
else
|
||||
">&2 echo 'Aborting, paperless-manage must be run as user `${cfg.user}`!'; exit 2"
|
||||
}
|
||||
@@ -123,7 +121,7 @@ let
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SupplementaryGroups = lib.optional enableRedis redisServer.group;
|
||||
SupplementaryGroups = lib.optional enableRedis redisServer.user;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
@@ -272,29 +270,7 @@ in
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = defaultUser;
|
||||
description = ''
|
||||
User under which Paperless runs
|
||||
|
||||
::: {.note}
|
||||
If left as the default value this user will automatically be
|
||||
created on system activation, otherwise you are responsible for
|
||||
ensuring the group exists before the paperless service starts.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = defaultUser;
|
||||
description = ''
|
||||
Primary group under which Paperless 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 redis service starts.
|
||||
:::
|
||||
'';
|
||||
description = "User under which Paperless runs.";
|
||||
};
|
||||
|
||||
package = lib.mkPackageOption pkgs "paperless-ngx" { } // {
|
||||
@@ -598,7 +574,7 @@ in
|
||||
# and automatically migrates when needed (e.g. with v2 -> v3 swapping from Whoosh to Tantivy)
|
||||
${lib.getExe cfg.package} document_index reindex --if-needed --no-progress-bar
|
||||
|
||||
if ${lib.boolToString (cfg.passwordFile != null)} || [[ -n ''${PAPERLESS_ADMIN_PASSWORD-} ]]; then
|
||||
if ${lib.boolToString (cfg.passwordFile != null)} || [[ -n $PAPERLESS_ADMIN_PASSWORD ]]; then
|
||||
export PAPERLESS_ADMIN_USER="''${PAPERLESS_ADMIN_USER:-admin}"
|
||||
if [[ -e $CREDENTIALS_DIRECTORY/PAPERLESS_ADMIN_PASSWORD ]]; then
|
||||
PAPERLESS_ADMIN_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/PAPERLESS_ADMIN_PASSWORD")
|
||||
|
||||
@@ -137,7 +137,6 @@ in
|
||||
|
||||
services.${systemdName} = {
|
||||
inherit description;
|
||||
path = [ config.programs.ssh.package ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.seerr;
|
||||
# 26.05 introduced a breaking change which is guarded behind stateRevision to
|
||||
# avoid breaking users.
|
||||
useNewConfigLocation = cfg.stateRevision >= 1;
|
||||
# 26.05 introduced a breaking change which is guarded behind stateVersion to avoid
|
||||
# breaking users.
|
||||
useNewConfigLocation = lib.versionAtLeast config.system.stateVersion "26.05";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
@@ -40,23 +39,8 @@ in
|
||||
configDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = if useNewConfigLocation then "/var/lib/seerr/" else "/var/lib/jellyseerr/config";
|
||||
defaultText = lib.literalMD "{file}`/var/lib/seerr` (or {file}`/var/lib/jellyseerr/config` if {option}`services.seerr.stateRevision` < 1)";
|
||||
description = "Config data directory";
|
||||
};
|
||||
|
||||
stateRevision = utils.mkStateRevisionOption {
|
||||
descriptionName = "Seerr";
|
||||
migrations = {
|
||||
"26.05" = ''
|
||||
Move {file}`/var/lib/private/jellyseerr/config` to
|
||||
{file}`/var/lib/private/seerr`, if you have not set
|
||||
{option}`services.seerr.configDir`. (If you have set
|
||||
{option}`services.seerr.configDir`, you should also have forced
|
||||
{option}`systemd.services.seerr.serviceConfig.StateDirectory`, and in
|
||||
that case `stateRevision` does not affect your configuration.)
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
@@ -97,7 +81,5 @@ in
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
|
||||
system.moduleStateRevisions."services.seerr.stateRevision" = cfg.stateRevision;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ let
|
||||
ln -s /run/wrappers/bin/cgroup-network $out/libexec/netdata/plugins.d/cgroup-network
|
||||
ln -s /run/wrappers/bin/debugfs.plugin $out/libexec/netdata/plugins.d/debugfs.plugin
|
||||
ln -s /run/wrappers/bin/freeipmi.plugin $out/libexec/netdata/plugins.d/freeipmi.plugin
|
||||
ln -s /run/wrappers/bin/go.d.plugin $out/libexec/netdata/plugins.d/go.d.plugin
|
||||
ln -s /run/wrappers/bin/logs-management.plugin $out/libexec/netdata/plugins.d/logs-management.plugin
|
||||
ln -s /run/wrappers/bin/network-viewer.plugin $out/libexec/netdata/plugins.d/network-viewer.plugin
|
||||
ln -s /run/wrappers/bin/otel-plugin $out/libexec/netdata/plugins.d/otel-plugin
|
||||
@@ -169,7 +168,7 @@ in
|
||||
`cfg.package` must be built with `withNdsudo = true`
|
||||
:::
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
example = ''
|
||||
[
|
||||
pkgs.smartmontools
|
||||
pkgs.nvme-cli
|
||||
@@ -370,10 +369,8 @@ in
|
||||
# Capabilities
|
||||
CapabilityBoundingSet = [
|
||||
"CAP_DAC_OVERRIDE" # is required for freeipmi and slabinfo plugins
|
||||
"CAP_DAC_READ_SEARCH" # is required for apps, systemd-journal and go.d/filecheck collector
|
||||
"CAP_NET_ADMIN" # is required for the go.d/wireguard collector
|
||||
"CAP_NET_BIND_SERVICE" # is required for the go.d/snmp_traps collector
|
||||
"CAP_NET_RAW" # is required for the go.d/ping collector
|
||||
"CAP_DAC_READ_SEARCH" # is required for apps and systemd-journal plugin
|
||||
"CAP_NET_RAW" # is required for fping app
|
||||
"CAP_PERFMON" # is required for perf plugin
|
||||
"CAP_SETPCAP" # is required for apps, perf and slabinfo plugins
|
||||
"CAP_SETUID" # is required for cgroups and cgroups-network plugins
|
||||
@@ -387,10 +384,7 @@ in
|
||||
"CAP_FOWNER"
|
||||
"CAP_SYS_RAWIO"
|
||||
]
|
||||
++ lib.optionals cfg.package.withNdsudo [
|
||||
"CAP_SETGID" # is required for ndsudo to fully acquire root privileges (setgid/setegid, alongside CAP_SETUID above)
|
||||
"CAP_SYS_RAWIO" # is required for ndsudo to run S.M.A.R.T./NVMe raw-IO commands (e.g. smartctl, nvme-cli)
|
||||
];
|
||||
++ lib.optional isThereAnyWireGuardTunnels "CAP_NET_ADMIN";
|
||||
# Sandboxing
|
||||
ProtectSystem = "full";
|
||||
ProtectHome = "read-only";
|
||||
@@ -436,22 +430,6 @@ in
|
||||
permissions = "u+rx,g+x,o-rwx";
|
||||
};
|
||||
|
||||
"go.d.plugin" = {
|
||||
source = "${cfg.package}/libexec/netdata/plugins.d/godplugin";
|
||||
# https://github.com/netdata/netdata/blob/master/src/go/plugin/go.d/README.md#required-linux-capabilities
|
||||
capabilities =
|
||||
lib.concatStringsSep "," [
|
||||
"cap_dac_read_search" # is required for the go.d/filecheck collector
|
||||
"cap_net_admin" # is required for the go.d/wireguard collector
|
||||
"cap_net_bind_service" # is required for the go.d/snmp_traps collector
|
||||
"cap_net_raw" # is required for the go.d/ping collector
|
||||
]
|
||||
+ "+eip";
|
||||
owner = cfg.user;
|
||||
group = cfg.group;
|
||||
permissions = "u+rx,g+x,o-rwx";
|
||||
};
|
||||
|
||||
"cgroup-network" = {
|
||||
source = "${cfg.package}/libexec/netdata/plugins.d/cgroup-network.org";
|
||||
capabilities = "cap_setuid+ep";
|
||||
|
||||
@@ -82,7 +82,6 @@ let
|
||||
"keylight"
|
||||
"klipper"
|
||||
"knot"
|
||||
"kvrocks"
|
||||
"libvirt"
|
||||
"lnd"
|
||||
"mail"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.prometheus.exporters.kvrocks;
|
||||
in
|
||||
{
|
||||
port = 9121;
|
||||
serviceOpts = {
|
||||
serviceConfig = {
|
||||
RestrictAddressFamilies = [ "AF_UNIX" ];
|
||||
ExecStart = "${lib.getExe pkgs.prometheus-kvrocks-exporter} -web.listen-address ${cfg.listenAddress}:${toString cfg.port} ${lib.escapeShellArgs cfg.extraFlags}";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -679,7 +679,7 @@ in
|
||||
environment = envVars;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${cfg.package}/bin/upsdrvctl -u root shutdown";
|
||||
ExecStart = "${cfg.package}/bin/upsdrvctl shutdown";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ in
|
||||
PrivateMounts = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = "strict";
|
||||
ProtectHome = true;
|
||||
|
||||
@@ -436,15 +436,6 @@ in
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"@chown setgroups setresuid"
|
||||
]
|
||||
++ lib.optionals pkgs.stdenv.hostPlatform.is32bit [
|
||||
# glibc's setresuid()/setgroups() invoke the kernel's 32-bit compat
|
||||
# syscalls (setresuid32/setgroups32) on 32-bit architectures --
|
||||
# distinct syscalls from the ones already allowlisted above, so
|
||||
# without these 2, avahi-daemon is killed with SIGSYS as soon as it
|
||||
# tries to drop privileges.
|
||||
"setgroups32"
|
||||
"setresuid32"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
let
|
||||
|
||||
cfg = config.services.dnscrypt-proxy;
|
||||
settingsFormat = pkgs.formats.toml { };
|
||||
|
||||
in
|
||||
|
||||
@@ -37,7 +36,7 @@ in
|
||||
};
|
||||
}
|
||||
'';
|
||||
type = settingsFormat.type;
|
||||
type = lib.types.attrs;
|
||||
default = { };
|
||||
};
|
||||
|
||||
|
||||
@@ -53,14 +53,6 @@ in
|
||||
The maximum log size.
|
||||
'';
|
||||
};
|
||||
|
||||
telemetry = lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = ''
|
||||
Collects anonymous usage data and crash reports.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -79,8 +71,8 @@ in
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
ExecStart = "${pkgs.eternal-terminal}/bin/etserver --logtostdout --cfgfile=${pkgs.writeText "et.cfg" ''
|
||||
Type = "forking";
|
||||
ExecStart = "${pkgs.eternal-terminal}/bin/etserver --daemon --cfgfile=${pkgs.writeText "et.cfg" ''
|
||||
; et.cfg : Config file for Eternal Terminal
|
||||
;
|
||||
|
||||
@@ -91,15 +83,15 @@ in
|
||||
verbose = ${toString cfg.verbosity}
|
||||
silent = ${if cfg.silent then "1" else "0"}
|
||||
logsize = ${toString cfg.logSize}
|
||||
telemetry = ${lib.boolToString cfg.telemetry}
|
||||
''}";
|
||||
Restart = "on-failure";
|
||||
KillMode = "process";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = with lib.maintainers; [ tomasrivera ];
|
||||
maintainers = [ ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ let
|
||||
ProtectSystem = "full";
|
||||
ProtectHome = "on";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
RestartSec = 2;
|
||||
LogsDirectory = "radius";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,8 +29,10 @@ in
|
||||
};
|
||||
|
||||
description = ''
|
||||
Configuration for GoDNS. Refer to the [configuration section](https://github.com/TimothyYe/godns?tab=readme-ov-file#configuration) in the
|
||||
Configuration for GoDNS. Refer to the [configuration section](1) in the
|
||||
GoDNS GitHub repository for details.
|
||||
|
||||
[1]: https://github.com/TimothyYe/godns?tab=readme-ov-file#configuration
|
||||
'';
|
||||
|
||||
example = {
|
||||
|
||||
@@ -795,7 +795,7 @@ in
|
||||
- {var}`"wpa2-sha256"`: WPA2-Personal using HMAC-SHA256 (IEEE 802.11i/RSN). Passwords are set
|
||||
using {option}`wpaPassword` or preferably by {option}`wpaPasswordFile` or {option}`wpaPskFile`.
|
||||
- {var}`"wpa3-sae-transition"`: Use WPA3-Personal (SAE) if possible, otherwise fallback
|
||||
to WPA2-Personal. Only use if necessary and switch to the newer WPA3-SAE when possible.
|
||||
to WPA2-SHA256. Only use if necessary and switch to the newer WPA3-SAE when possible.
|
||||
You will have to specify both {option}`wpaPassword` and {option}`saePasswords` (or one of their alternatives).
|
||||
- {var}`"wpa3-sae"`: Use WPA3-Personal (SAE). This is currently the recommended way to
|
||||
setup a secured WiFi AP (as of March 2023) and therefore the default. Passwords are set
|
||||
@@ -803,27 +803,6 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
transitionDisable = mkOption {
|
||||
default = false;
|
||||
example = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Enable the WPA3-Personal Transition Disable indication. After a successful
|
||||
WPA3 association, compatible stations will disable WPA2-Personal for this
|
||||
network profile, protecting subsequent associations against downgrade attacks.
|
||||
Legacy stations can still connect using WPA2 in transition mode.
|
||||
|
||||
This option is supported in `"wpa3-sae"` and `"wpa3-sae-transition"` modes.
|
||||
|
||||
::: {.warning}
|
||||
Enable this only when every BSS in the network using this SSID supports
|
||||
WPA3-Personal. The indication applies to a station's entire network profile
|
||||
and can prevent it from connecting to WPA2-only BSSs. Therefore, the WPA3 spec
|
||||
requires this to be disabled by default.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
pairwiseCiphers = mkOption {
|
||||
default = [ "CCMP" ];
|
||||
example = [
|
||||
@@ -1096,12 +1075,15 @@ in
|
||||
wpa_key_mgmt = "SAE";
|
||||
# Derive PWE using both hunting-and-pecking loop and hash-to-element
|
||||
sae_pwe = 2;
|
||||
# Prevent downgrade attacks by indicating to clients that they should
|
||||
# disable any transition modes from now on.
|
||||
transition_disable = "0x01";
|
||||
# Per WPA3 spec, MFP is required.
|
||||
ieee80211w = 2;
|
||||
}
|
||||
// optionalAttrs (bssCfg.authentication.mode == "wpa3-sae-transition") {
|
||||
wpa = 2;
|
||||
wpa_key_mgmt = "WPA-PSK WPA-PSK-SHA256 SAE";
|
||||
wpa_key_mgmt = "WPA-PSK-SHA256 SAE";
|
||||
ieee80211w = 1;
|
||||
}
|
||||
// optionalAttrs (bssCfg.authentication.mode == "wpa2-sha1") {
|
||||
@@ -1118,9 +1100,6 @@ in
|
||||
wpa_pairwise = pairwiseCiphers;
|
||||
rsn_pairwise = pairwiseCiphers;
|
||||
}
|
||||
// optionalAttrs bssCfg.authentication.transitionDisable {
|
||||
transition_disable = "0x01";
|
||||
}
|
||||
// optionalAttrs (bssCfg.authentication.wpaPassword != null) {
|
||||
wpa_passphrase = bssCfg.authentication.wpaPassword;
|
||||
}
|
||||
@@ -1432,15 +1411,6 @@ in
|
||||
assertion = auth.saePasswords == [ ] || auth.saePasswordsFile == null;
|
||||
message = "hostapd radio ${radio} bss ${bss}: must use only one SAE password option (saePasswords or saePasswordsFile)";
|
||||
}
|
||||
{
|
||||
assertion =
|
||||
auth.transitionDisable
|
||||
-> builtins.elem auth.mode [
|
||||
"wpa3-sae"
|
||||
"wpa3-sae-transition"
|
||||
];
|
||||
message = "hostapd radio ${radio} bss ${bss}: transitionDisable requires WPA3-SAE or WPA3-SAE transition mode";
|
||||
}
|
||||
{
|
||||
assertion = auth.mode == "wpa3-sae" -> (auth.saePasswords != [ ] || auth.saePasswordsFile != null);
|
||||
message = "hostapd radio ${radio} bss ${bss}: uses WPA3-SAE which requires defining a sae password option";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.krill;
|
||||
toml = pkgs.formats.toml { };
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = [ lib.maintainers.stepbrobd ];
|
||||
teams = [ lib.teams.ngi ];
|
||||
};
|
||||
|
||||
options.services.krill = {
|
||||
enable = lib.mkEnableOption "Krill, RPKI CA and Publication Server";
|
||||
|
||||
package = lib.mkPackageOption pkgs "krill" { };
|
||||
|
||||
environmentFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/run/secrets/krill";
|
||||
description = ''
|
||||
Environment file for krill.
|
||||
|
||||
Krill requires an admin token to start.
|
||||
Use this file to provide `KRILL_ADMIN_TOKEN=...`
|
||||
(e.g. via agenix or sops-nix).
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = toml.type;
|
||||
options = {
|
||||
storage_uri = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/var/lib/krill/data";
|
||||
description = ''
|
||||
Where Krill stores its data e.g. CA keys and the publication repository.
|
||||
The default keeps it inside service state directory.
|
||||
'';
|
||||
};
|
||||
log_type = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"stderr"
|
||||
"file"
|
||||
"syslog"
|
||||
];
|
||||
default = "stderr";
|
||||
description = "Where Krill logs to.";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
Configuration written to `krill.conf`.
|
||||
See <https://krill.docs.nlnetlabs.nl/en/stable/config.html> for available options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
systemd.services.krill = {
|
||||
description = "Krill RPKI CA and Publication Server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
ExecStart = "${lib.getExe' cfg.package "krill"} --config ${toml.generate "krill.conf" cfg.settings}";
|
||||
EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile;
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
StateDirectory = "krill";
|
||||
StateDirectoryMode = "0700";
|
||||
RuntimeDirectory = "krill";
|
||||
UMask = "0077";
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
DynamicUser = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateTmp = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallFilter = "@system-service";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -52,7 +52,6 @@ in
|
||||
for possible values.
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = yaml.type;
|
||||
options.repo = {
|
||||
scanPath = mkOption {
|
||||
type = types.path;
|
||||
@@ -61,12 +60,7 @@ in
|
||||
};
|
||||
readme = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"readme"
|
||||
"README"
|
||||
"readme.md"
|
||||
"README.md"
|
||||
];
|
||||
default = [ ];
|
||||
description = "Readme files to look for.";
|
||||
};
|
||||
mainBranch = mkOption {
|
||||
@@ -86,14 +80,14 @@ in
|
||||
options.dirs = {
|
||||
templates = mkOption {
|
||||
type = types.path;
|
||||
default = "${cfg.package}/lib/legit/templates";
|
||||
defaultText = literalExpression ''"''${config.services.legit.package}/lib/legit/templates"'';
|
||||
default = "${pkgs.legit-web}/lib/legit/templates";
|
||||
defaultText = literalExpression ''"''${pkgs.legit-web}/lib/legit/templates"'';
|
||||
description = "Directories where template files are located.";
|
||||
};
|
||||
static = mkOption {
|
||||
type = types.path;
|
||||
default = "${cfg.package}/lib/legit/static";
|
||||
defaultText = literalExpression ''"''${config.services.legit.package}/lib/legit/static"'';
|
||||
default = "${pkgs.legit-web}/lib/legit/static";
|
||||
defaultText = literalExpression ''"''${pkgs.legit-web}/lib/legit/static"'';
|
||||
description = "Directories where static files are located.";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ in
|
||||
any_failed=0
|
||||
|
||||
addList() {
|
||||
local payload="$1" result type id error
|
||||
local payload="$1" result type error
|
||||
|
||||
echo "Adding list: $payload"
|
||||
type=$($jq -r '.type' <<< "$payload")
|
||||
@@ -49,25 +49,17 @@ in
|
||||
|
||||
error="$($jq '.error' <<< "$result")"
|
||||
if [[ "$error" != "null" ]]; then
|
||||
if $jq -e '
|
||||
.error.key == "database_error"
|
||||
and .error.hint == "The item is already present"
|
||||
' <<< "$result" > /dev/null; then
|
||||
echo "List already present"
|
||||
echo "Error: $error"
|
||||
any_failed=1
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Error: $error"
|
||||
any_failed=1
|
||||
return
|
||||
fi
|
||||
|
||||
id="$($jq '.lists.[].id?' <<< "$result")"
|
||||
if [[ "$id" == "null" ]]; then
|
||||
any_failed=1
|
||||
error="$($jq '.processed.errors.[].error' <<< "$result")"
|
||||
echo "Error: $error"
|
||||
return
|
||||
any_failed=1
|
||||
error="$($jq '.processed.errors.[].error' <<< "$result")"
|
||||
echo "Error: $error"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Added list ID $id: $result"
|
||||
|
||||
@@ -144,9 +144,6 @@ in
|
||||
"2270002"
|
||||
"2270003"
|
||||
"2270004"
|
||||
"2270005"
|
||||
"2270006"
|
||||
"2270007"
|
||||
];
|
||||
description = ''
|
||||
List of rules that should be disabled.
|
||||
@@ -273,7 +270,7 @@ in
|
||||
ProtectSystem = "strict";
|
||||
DevicePolicy = "closed";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
ProtectHostname = true;
|
||||
ProtectProc = true;
|
||||
ProtectKernelLogs = true;
|
||||
|
||||
@@ -96,20 +96,6 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
importLegacyState = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = !cfg.static;
|
||||
defaultText = lib.literalExpression "!config.services.userborn.static";
|
||||
description = ''
|
||||
Whether to include one-shot migration services that import the state
|
||||
left behind by the perl activation script (`update-users-groups.pl`),
|
||||
so id and subid allocations survive the switch to userborn.
|
||||
|
||||
Disable this if you want to keep the migration tooling out of your
|
||||
system closure.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
@@ -155,33 +141,6 @@ in
|
||||
) userCfg.users
|
||||
);
|
||||
|
||||
# One-shot import of update-users-groups.pl state. Runs before
|
||||
# userborn so removed users' ids are reserved before allocation.
|
||||
# Remove once the perl path has been gone for two releases.
|
||||
services.userborn-import-legacy = lib.mkIf cfg.importLegacyState {
|
||||
wantedBy = [ "sysinit.target" ];
|
||||
requiredBy = [ "userborn.service" ];
|
||||
before = [
|
||||
"userborn.service"
|
||||
"shutdown.target"
|
||||
];
|
||||
after = [ "systemd-remount-fs.service" ];
|
||||
conflicts = [ "shutdown.target" ];
|
||||
unitConfig = {
|
||||
Description = "Import legacy update-users-groups.pl state for userborn";
|
||||
DefaultDependencies = false;
|
||||
ConditionPathExists = [
|
||||
"/var/lib/nixos/uid-map"
|
||||
"!/var/lib/userborn"
|
||||
];
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = "${lib.getExe pkgs.userborn-import-legacy} --nogroup-gid ${toString config.ids.gids.nogroup} ${cfg.passwordFilesLocation}";
|
||||
};
|
||||
};
|
||||
|
||||
services.userborn = lib.mkIf (!cfg.static) {
|
||||
wantedBy = [ "sysinit.target" ];
|
||||
requiredBy = [ "sysinit-reactivation.target" ];
|
||||
|
||||
@@ -28,19 +28,17 @@ let
|
||||
|
||||
gettyCmd = args: "${lib.getExe' pkgs.util-linux "agetty"} ${escapeShellArgs baseArgs} ${args}";
|
||||
|
||||
autologinOnceScript =
|
||||
otherArgs:
|
||||
pkgs.writeShellApplication {
|
||||
name = "autologin-once";
|
||||
text = ''
|
||||
autologged="/run/agetty.autologged"
|
||||
if test "$TTY" = tty1 && ! test -f "$autologged"; then
|
||||
touch "$autologged"
|
||||
exec ${gettyCmd "${otherArgs} --autologin ${cfg.autologinUser}"}
|
||||
fi
|
||||
exec ${gettyCmd otherArgs}
|
||||
'';
|
||||
};
|
||||
autologinScript = ''
|
||||
otherArgs="--noclear --keep-baud $TTY 115200,38400,9600 $TERM";
|
||||
${lib.optionalString cfg.autologinOnce ''
|
||||
autologged="/run/agetty.autologged"
|
||||
if test "$TTY" = tty1 && ! test -f "$autologged"; then
|
||||
touch "$autologged"
|
||||
exec ${gettyCmd "$otherArgs --autologin ${cfg.autologinUser}"}
|
||||
fi
|
||||
''}
|
||||
exec ${gettyCmd "$otherArgs"}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
@@ -181,12 +179,7 @@ in
|
||||
serviceConfig.ExecStart = [
|
||||
# override upstream default with an empty ExecStart
|
||||
""
|
||||
(
|
||||
if cfg.autologinOnce then
|
||||
lib.getExe (autologinOnceScript ''--noclear --keep-baud "$TTY" 115200,38400,9600 "$TERM"'')
|
||||
else
|
||||
gettyCmd "--noclear --keep-baud %I 115200,38400,9600 $TERM"
|
||||
)
|
||||
(pkgs.writers.writeDash "getty" autologinScript)
|
||||
];
|
||||
environment.TTY = "%I";
|
||||
restartIfChanged = false;
|
||||
|
||||
@@ -35,7 +35,7 @@ let
|
||||
enableAutologin:
|
||||
"${gettyCfg.loginProgram} ${baseLoginOptions}${lib.optionalString enableAutologin " -f -- ${gettyCfg.autologinUser}"}";
|
||||
|
||||
loginScript = pkgs.writers.writeBash "kmscon-login" (
|
||||
loginScript = pkgs.writers.writeDash "kmscon-login" (
|
||||
lib.optionalString (gettyCfg.autologinUser != null && gettyCfg.autologinOnce) ''
|
||||
kms_tty=
|
||||
active_tty_file=/sys/class/tty/tty0/active
|
||||
|
||||
@@ -641,8 +641,6 @@ in
|
||||
s3_http_continue_timeout = null;
|
||||
s3_install_cors_rule = null;
|
||||
s3_asset_cdn_url = null;
|
||||
s3_role_arn = null;
|
||||
s3_role_session_name = null;
|
||||
|
||||
max_user_api_reqs_per_minute = 20;
|
||||
max_user_api_reqs_per_day = 2880;
|
||||
@@ -669,6 +667,7 @@ in
|
||||
compress_anon_cache = false;
|
||||
anon_cache_store_threshold = 2;
|
||||
allowed_theme_repos = null;
|
||||
enable_email_sync_demon = false;
|
||||
max_digests_enqueued_per_30_mins_per_site = 10000;
|
||||
cluster_name = null;
|
||||
multisite_config_path = "config/multisite.yml";
|
||||
@@ -682,10 +681,6 @@ in
|
||||
allow_impersonation = true;
|
||||
log_line_max_chars = 160000;
|
||||
yjit_enabled = false;
|
||||
# this option is set to `true` in discourse's defaults.
|
||||
# however, having this option enabled appears to cause a segfault in mini_racer
|
||||
# see https://github.com/rubyjs/mini_racer/issues/422
|
||||
mini_racer_single_threaded = false;
|
||||
};
|
||||
|
||||
services.redis.servers.discourse =
|
||||
@@ -956,35 +951,27 @@ in
|
||||
# asset pipeline enables this
|
||||
brotli_static on;
|
||||
gzip_static on;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
'';
|
||||
"~ ^/plugins/".extraConfig = cache_1y;
|
||||
"~ /images/emoji/".extraConfig = cache_1y;
|
||||
"~ ^/uploads/" = proxy {
|
||||
extraConfig = ''
|
||||
extraConfig = cache_1y + ''
|
||||
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
|
||||
proxy_set_header X-Accel-Mapping ${cfg.package}/share/discourse/public/=/downloads/;
|
||||
|
||||
# custom CSS
|
||||
location ~ /stylesheet-cache/ {
|
||||
${cache_1y}
|
||||
try_files $uri =404;
|
||||
}
|
||||
# this allows us to bypass rails
|
||||
location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|ico|webp)$ {
|
||||
${cache_1y}
|
||||
try_files $uri =404;
|
||||
}
|
||||
# force attachment so SVGs can't render as a document on direct navigation
|
||||
# SVG needs an extra header attached
|
||||
location ~* \.(svg)$ {
|
||||
${cache_1y}
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Content-Disposition attachment;
|
||||
try_files $uri =404;
|
||||
}
|
||||
# thumbnails & optimized images
|
||||
location ~ /_?optimized/ {
|
||||
${cache_1y}
|
||||
try_files $uri =404;
|
||||
}
|
||||
'';
|
||||
|
||||
@@ -132,7 +132,6 @@ in
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"@chown"
|
||||
];
|
||||
# User and group
|
||||
DynamicUser = true;
|
||||
|
||||
@@ -239,14 +239,11 @@ in
|
||||
|
||||
serviceConfig = commonConfig // {
|
||||
Restart = "always";
|
||||
ExecStartPre =
|
||||
lib.optionals (cfg.settings.DEBUG != "True") [
|
||||
"${pkg}/opt/healthchecks/manage.py compress"
|
||||
]
|
||||
++ [
|
||||
"${pkg}/opt/healthchecks/manage.py collectstatic --no-input"
|
||||
"${pkg}/opt/healthchecks/manage.py remove_stale_contenttypes --no-input"
|
||||
];
|
||||
ExecStartPre = [
|
||||
"${pkg}/opt/healthchecks/manage.py collectstatic --no-input"
|
||||
"${pkg}/opt/healthchecks/manage.py remove_stale_contenttypes --no-input"
|
||||
]
|
||||
++ lib.optionals (cfg.settings.DEBUG != "True") [ "${pkg}/opt/healthchecks/manage.py compress" ];
|
||||
ExecStart = ''
|
||||
${pkgs.python3Packages.gunicorn}/bin/gunicorn hc.wsgi \
|
||||
--bind ${cfg.listenAddress}:${toString cfg.port} \
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.hister;
|
||||
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
|
||||
dataDir = if cfg.dataDir != null then cfg.dataDir else "/var/lib/hister";
|
||||
generatedConfig = yamlFormat.generate "hister-config.yml" cfg.settings;
|
||||
hasConfig = cfg.configPath != null || cfg.settings != { };
|
||||
runtimeConfigSource = if cfg.settings != { } then generatedConfig else cfg.configPath;
|
||||
runtimeConfig = "/run/hister/config.yml";
|
||||
|
||||
histerEnv =
|
||||
lib.optionalAttrs (cfg.port != null) {
|
||||
HISTER_PORT = toString cfg.port;
|
||||
}
|
||||
// lib.optionalAttrs hasConfig {
|
||||
HISTER_CONFIG = runtimeConfig;
|
||||
}
|
||||
// {
|
||||
HISTER_DATA_DIR = dataDir;
|
||||
};
|
||||
|
||||
privilegedPort = cfg.port != null && cfg.port < 1024;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ _4evy ];
|
||||
|
||||
options.services.hister = {
|
||||
enable = lib.mkEnableOption "Hister, a web history service with content-based search";
|
||||
|
||||
package = lib.mkPackageOption pkgs "hister" { };
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "hister";
|
||||
description = "User account under which Hister runs.";
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "hister";
|
||||
description = "Group under which Hister runs.";
|
||||
};
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/var/lib/hister";
|
||||
description = ''
|
||||
Directory where Hister stores its data. When `null` (the default), the
|
||||
service is isolated under `/var/lib/hister` via systemd's
|
||||
`StateDirectory=`. When set to an explicit path, that path is created
|
||||
with `systemd-tmpfiles` and granted via `ReadWritePaths=` instead.
|
||||
'';
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.port;
|
||||
default = null;
|
||||
example = 4433;
|
||||
description = ''
|
||||
Port on which Hister listens. When set, this overrides the port in
|
||||
`server.address` from the configuration file via the `HISTER_PORT`
|
||||
environment variable.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to open {option}`services.hister.port` in the firewall. Has no
|
||||
effect if `port` is `null`.
|
||||
'';
|
||||
};
|
||||
|
||||
configPath = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/etc/hister/config.yml";
|
||||
description = ''
|
||||
Path to an existing Hister configuration file mounted read-only into
|
||||
the service runtime directory and passed via `HISTER_CONFIG`. Mutually
|
||||
exclusive with {option}`services.hister.settings`.
|
||||
'';
|
||||
};
|
||||
|
||||
environmentFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/run/secrets/hister.env";
|
||||
description = ''
|
||||
Path to an environment file (read at service start) used to inject
|
||||
secrets such as `HISTER__APP__ACCESS_TOKEN` without placing them in the
|
||||
world-readable Nix store.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = yamlFormat.type;
|
||||
default = { };
|
||||
description = ''
|
||||
Hister configuration rendered to YAML and passed via `HISTER_CONFIG`.
|
||||
Accepts any structure the server accepts: see the `app`, `server`,
|
||||
`indexer`, `crawler`, `hotkeys`, `extractors`, `semantic_search`, and
|
||||
`sensitive_content_patterns` blocks documented upstream.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
app = {
|
||||
search_url = "https://google.com/search?q={query}";
|
||||
log_level = "info";
|
||||
};
|
||||
server = {
|
||||
address = "127.0.0.1:4433";
|
||||
database = "db.sqlite3";
|
||||
};
|
||||
hotkeys.web = {
|
||||
"/" = "focus_search_input";
|
||||
"enter" = "open_result";
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = !(cfg.configPath != null && cfg.settings != { });
|
||||
message = "Only one of services.hister.configPath and services.hister.settings can be set";
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
users.users = lib.mkIf (cfg.user == "hister") {
|
||||
hister = {
|
||||
description = "Hister web history service";
|
||||
group = cfg.group;
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = lib.mkIf (cfg.group == "hister") {
|
||||
hister = { };
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."10-hister"."${dataDir}".d = lib.mkIf (cfg.dataDir != null) {
|
||||
user = cfg.user;
|
||||
group = cfg.group;
|
||||
mode = "0750";
|
||||
};
|
||||
|
||||
systemd.services.hister = {
|
||||
description = "Hister web history service";
|
||||
after = [
|
||||
"network.target"
|
||||
"systemd-tmpfiles-setup.service"
|
||||
"systemd-tmpfiles-resetup.service"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
environment = histerEnv;
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${lib.getExe cfg.package} listen";
|
||||
Restart = "on-failure";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
RuntimeDirectory = lib.mkIf hasConfig "hister";
|
||||
RuntimeDirectoryMode = lib.mkIf hasConfig "0750";
|
||||
BindReadOnlyPaths = lib.mkIf hasConfig [ "${runtimeConfigSource}:${runtimeConfig}" ];
|
||||
StateDirectory = lib.mkIf (cfg.dataDir == null) "hister";
|
||||
StateDirectoryMode = lib.mkIf (cfg.dataDir == null) "0750";
|
||||
ReadWritePaths = lib.mkIf (cfg.dataDir != null) [ cfg.dataDir ];
|
||||
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
|
||||
|
||||
AmbientCapabilities = lib.mkIf privilegedPort [ "CAP_NET_BIND_SERVICE" ];
|
||||
CapabilityBoundingSet = if privilegedPort then [ "CAP_NET_BIND_SERVICE" ] else [ "" ];
|
||||
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectClock = true;
|
||||
ProtectHostname = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
LockPersonality = true;
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
MemoryDenyWriteExecute = true;
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.mkIf (cfg.openFirewall && cfg.port != null) [ cfg.port ];
|
||||
};
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
options,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.homebox;
|
||||
inherit (lib)
|
||||
literalExpression
|
||||
mkEnableOption
|
||||
mkPackageOption
|
||||
mkDefault
|
||||
@@ -19,11 +17,6 @@ let
|
||||
|
||||
defaultUser = "homebox";
|
||||
defaultGroup = "homebox";
|
||||
|
||||
pepperDefault =
|
||||
(cfg.secrets ? HBOX_AUTH_API_KEY_PEPPER)
|
||||
&& (cfg.secrets.HBOX_AUTH_API_KEY_PEPPER == "/var/lib/homebox/api-pepper-secret");
|
||||
opts = options.services.homebox;
|
||||
in
|
||||
{
|
||||
options.services.homebox = {
|
||||
@@ -68,37 +61,6 @@ in
|
||||
'';
|
||||
};
|
||||
};
|
||||
secrets = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
HBOX_AUTH_API_KEY_PEPPER = mkOption {
|
||||
type = types.externalPath;
|
||||
default = "/var/lib/homebox/api-pepper-secret";
|
||||
description = ''
|
||||
Path to the API key pepper secret file (required for homebox to start).
|
||||
'';
|
||||
example = "/run/secrets/homebox-api-pepper";
|
||||
};
|
||||
};
|
||||
freeformType = types.attrsOf types.externalPath;
|
||||
};
|
||||
|
||||
default = { };
|
||||
description = ''
|
||||
This follows the same structure as {option}`${opts.settings}`
|
||||
but the value of each key is a path.
|
||||
|
||||
The specified secret path is then read by systemd via [`LoadCredential=`]
|
||||
and templated into {option}`${opts.settings}` for you.
|
||||
|
||||
[`LoadCredential=`]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Credentials
|
||||
'';
|
||||
example = literalExpression ''
|
||||
{
|
||||
HBOX_AUTH_API_KEY_PEPPER = "/run/secrets/homebox-api-pepper";
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
@@ -130,7 +92,7 @@ in
|
||||
HBOX_DATABASE_DRIVER = "sqlite3";
|
||||
HBOX_DATABASE_SQLITE_PATH = "/var/lib/homebox/data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1";
|
||||
HBOX_OPTIONS_ALLOW_REGISTRATION = "false";
|
||||
HBOX_OPTIONS_GITHUB_RELEASE_CHECK = "false";
|
||||
HBOX_OPTIONS_CHECK_GITHUB_RELEASE = "false";
|
||||
HBOX_MODE = "production";
|
||||
# Fix this startup issue:
|
||||
# failed to create modcache index dir: mkdir /var/empty/.cache: read-only file system
|
||||
@@ -159,92 +121,58 @@ in
|
||||
}
|
||||
];
|
||||
};
|
||||
systemd.services.homebox-setup = mkIf pepperDefault {
|
||||
script = ''
|
||||
if [ ! -r "$STATE_DIRECTORY"/api-pepper-secret ]; then
|
||||
umask 0277
|
||||
openssl rand -base64 48 > "$STATE_DIRECTORY"/api-pepper-secret
|
||||
fi
|
||||
systemd.services.homebox = {
|
||||
requires = lib.optional cfg.database.createLocally "postgresql.target";
|
||||
after = lib.optional cfg.database.createLocally "postgresql.target";
|
||||
environment = lib.filterAttrs (_: v: v != null) cfg.settings;
|
||||
preStart = ''
|
||||
"${pkgs.coreutils}/bin/rm" -rf /var/lib/homebox/tmp
|
||||
"${pkgs.coreutils}/bin/mkdir" -p /var/lib/homebox/tmp
|
||||
'';
|
||||
path = [
|
||||
pkgs.openssl
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStart = lib.getExe cfg.package;
|
||||
LimitNOFILE = "1048576";
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
Restart = "always";
|
||||
StateDirectory = "homebox";
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet = "";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
PrivateUsers = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_NETLINK"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"@pkey"
|
||||
];
|
||||
RestrictSUIDSGID = true;
|
||||
PrivateMounts = true;
|
||||
UMask = "0077";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
systemd.services.homebox =
|
||||
let
|
||||
deps =
|
||||
lib.optionals pepperDefault [
|
||||
"homebox-setup.service"
|
||||
]
|
||||
++ lib.optionals cfg.database.createLocally [
|
||||
"postgresql.target"
|
||||
];
|
||||
in
|
||||
{
|
||||
requires = deps;
|
||||
after = deps;
|
||||
environment = lib.filterAttrs (_: v: v != null) cfg.settings;
|
||||
preStart = ''
|
||||
"${pkgs.coreutils}/bin/rm" -rf /var/lib/homebox/tmp
|
||||
"${pkgs.coreutils}/bin/mkdir" -p /var/lib/homebox/tmp
|
||||
'';
|
||||
script = ''
|
||||
${lib.strings.concatLines (
|
||||
lib.mapAttrsToList (name: _: "export ${name}=$(<\"$CREDENTIALS_DIRECTORY\"/${name})") cfg.secrets
|
||||
)}
|
||||
|
||||
exec ${lib.getExe cfg.package}
|
||||
'';
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
LoadCredential = (lib.mapAttrsToList (name: path: "${name}:${path}") cfg.secrets);
|
||||
LimitNOFILE = "1048576";
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
Restart = "always";
|
||||
StateDirectory = "homebox";
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet = "";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
PrivateUsers = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_NETLINK"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"@pkey"
|
||||
];
|
||||
RestrictSUIDSGID = true;
|
||||
PrivateMounts = true;
|
||||
UMask = "0077";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
};
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
patrickdag
|
||||
|
||||
@@ -208,13 +208,7 @@ in
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
# Flag `attach_disconnected` is necessary
|
||||
# because the PostgreSQL socket path appears
|
||||
# as a "disconnected" path: `run/postgresql/.s.PGSQL.XXXX`,
|
||||
# without the trailing slash, which AppArmor can't resolve.
|
||||
# The flag prepends a `/`, which isn't recommended,
|
||||
# but there aren't any alternative currently.
|
||||
profile ${cfg.package}/bin/miniflux flags=(attach_disconnected) {
|
||||
profile ${cfg.package}/bin/miniflux {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/ssl_certs>
|
||||
@@ -222,8 +216,6 @@ in
|
||||
include "${pkgs.apparmorRulesFromClosure { name = "miniflux"; } cfg.package}"
|
||||
${cfg.package}/bin/miniflux r,
|
||||
/run/miniflux/** rw,
|
||||
/run/postgresql/.s.PGSQL.* rw,
|
||||
/run/credentials/** r,
|
||||
include if exists <local/bin.miniflux>
|
||||
}
|
||||
'';
|
||||
|
||||
@@ -66,9 +66,7 @@ in
|
||||
WorkingDirectory = "/var/lib/readeck";
|
||||
EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile;
|
||||
DynamicUser = true;
|
||||
# readeck opens config.toml as writable in case it needs to add a secret key...
|
||||
ExecStartPre = "${lib.getExe' pkgs.coreutils "cp"} --no-preserve=all ${configFile} config.toml";
|
||||
ExecStart = "${lib.getExe cfg.package} serve -config config.toml";
|
||||
ExecStart = "${lib.getExe cfg.package} serve -config ${configFile}";
|
||||
ProtectSystem = "full";
|
||||
SystemCallArchitectures = "native";
|
||||
MemoryDenyWriteExecute = true;
|
||||
|
||||
@@ -90,7 +90,6 @@ let
|
||||
"unixd"
|
||||
"slotmem_shm"
|
||||
"socache_shmcb"
|
||||
"systemd"
|
||||
"mpm_${cfg.mpm}"
|
||||
]
|
||||
++ (if cfg.mpm == "prefork" then [ "cgi" ] else [ "cgid" ])
|
||||
@@ -993,12 +992,12 @@ in
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkg}/bin/httpd -D FOREGROUND -f /etc/httpd/httpd.conf";
|
||||
ExecStart = "@${pkg}/bin/httpd httpd -f /etc/httpd/httpd.conf";
|
||||
ExecStop = "${pkg}/bin/httpd -f /etc/httpd/httpd.conf -k graceful-stop";
|
||||
ExecReload = "${pkg}/bin/httpd -f /etc/httpd/httpd.conf -k graceful";
|
||||
KillMode = "mixed";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
Type = "notify";
|
||||
Type = "forking";
|
||||
PIDFile = "${runtimeDir}/httpd.pid";
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
|
||||
@@ -1614,7 +1614,11 @@ in
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # for pcre2 & several plugins
|
||||
MemoryDenyWriteExecute =
|
||||
!(
|
||||
(builtins.any (mod: (mod.allowMemoryWriteExecute or false)) cfg.package.modules)
|
||||
|| (lib.getName cfg.package == "openresty")
|
||||
);
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
|
||||
@@ -139,7 +139,7 @@ in
|
||||
"AF_INET6"
|
||||
];
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = false; # pcre2 jit
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
PrivateMounts = true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user