mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-06 17:13:24 -05:00
Merge d9c4084332 into haskell-updates
This commit is contained in:
commit
cac8c10692
1008 changed files with 18836 additions and 9960 deletions
2
.github/workflows/teams.yml
vendored
2
.github/workflows/teams.yml
vendored
|
|
@ -2,7 +2,7 @@ name: Teams
|
|||
|
||||
on:
|
||||
schedule:
|
||||
# Every Tuesday at 19:42 (randomly chosen)
|
||||
# Every Monday at 19:42 (randomly chosen)
|
||||
- cron: '42 19 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -17,6 +17,7 @@ jopejoe1 <nixpkgs@missing.ninja> <34899572+jopejoe1@users.noreply.github.com>
|
|||
jopejoe1 <nixpkgs@missing.ninja> <jopejoe1@missing.ninja>
|
||||
jopejoe1 <nixpkgs@missing.ninja> <jopejoe1>
|
||||
Jörg Thalheim <joerg@thalheim.io> <Mic92@users.noreply.github.com>
|
||||
Katalin Rebhan <me@dblsaiko.net>
|
||||
Lin Jian <me@linj.tech> <linj.dev@outlook.com>
|
||||
Lin Jian <me@linj.tech> <75130626+jian-lin@users.noreply.github.com>
|
||||
Martin Weinelt <hexa@darmstadt.ccc.de> <mweinelt@users.noreply.github.com>
|
||||
|
|
|
|||
|
|
@ -411,9 +411,9 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
|
|||
/pkgs/development/compilers/go @kalbasit @katexochen @Mic92
|
||||
|
||||
# GNOME
|
||||
/pkgs/desktops/gnome @jtojnar
|
||||
/pkgs/desktops/gnome/extensions @jtojnar
|
||||
/pkgs/build-support/make-hardcode-gsettings-patch @jtojnar
|
||||
/pkgs/desktops/gnome @NixOS/gnome
|
||||
/pkgs/desktops/gnome/extensions @NixOS/gnome
|
||||
/pkgs/build-support/make-hardcode-gsettings-patch @NixOS/gnome
|
||||
|
||||
# Cinnamon
|
||||
/pkgs/by-name/ci/cinnamon-* @mkg20001
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
},
|
||||
"branch": "nixpkgs-unstable",
|
||||
"submodules": false,
|
||||
"revision": "02f3fa0374fa13707d42d55d58ecc76b091f223c",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/02f3fa0374fa13707d42d55d58ecc76b091f223c.tar.gz",
|
||||
"hash": "0z8d33c5g0gk9a74ppqq77npisf9xx9c8ai9isxa2hyjx4lv1pki"
|
||||
"revision": "cbb5cf358f50aa6acc9efd6113b7bcfbc352cd73",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/cbb5cf358f50aa6acc9efd6113b7bcfbc352cd73.tar.gz",
|
||||
"hash": "sha256-IX7G1dlKrOqPOImfbo7ADDfV5yU1+j+MRChI3TL4tAA="
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"type": "Git",
|
||||
|
|
@ -22,10 +22,10 @@
|
|||
},
|
||||
"branch": "main",
|
||||
"submodules": false,
|
||||
"revision": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
|
||||
"url": "https://github.com/numtide/treefmt-nix/archive/790751ff7fd3801feeaf96d7dc416a8d581265ba.tar.gz",
|
||||
"hash": "1zah3dmbpn3ap5acg22kq1j19dg32gj73l43yamjcxhc38sv9kd5"
|
||||
"revision": "db947814a175b7ca6ded66e21383d938df01c227",
|
||||
"url": "https://github.com/numtide/treefmt-nix/archive/db947814a175b7ca6ded66e21383d938df01c227.tar.gz",
|
||||
"hash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM="
|
||||
}
|
||||
},
|
||||
"version": 5
|
||||
"version": 8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p npins
|
||||
#!nix-shell -i bash -p npins -I nixpkgs=../
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
npins --lock-file pinned.json upgrade
|
||||
npins --lock-file pinned.json update
|
||||
|
|
|
|||
|
|
@ -98,6 +98,14 @@ It has two modes:
|
|||
|
||||
: The path to the files to check.
|
||||
|
||||
`relocatable` (boolean, optional) {#tester-lycheeLinkCheck-param-relocatable}
|
||||
|
||||
: Whether the site is expected to be relocatable, i.e. servable from any URL path prefix.
|
||||
|
||||
When `true` (the default), root-relative links (starting with `/`) are treated as errors, because they break when the site is served from a subpath or opened via `file://` URLs.
|
||||
|
||||
When `false`, root-relative links are resolved against the `site` directory.
|
||||
|
||||
`remap` (attribute set, optional) {#tester-lycheeLinkCheck-param-remap}
|
||||
|
||||
: An attribute set where the attribute names are regular expressions.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,13 @@
|
|||
|
||||
- `uhttpmock` providing 0.0 ABI was removed. `uhttpmock_1_0` providing 1.0 ABI was renamed to `uhttpmock` and `uhttpmock_1_0` was kept as an alias.
|
||||
|
||||
- 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.
|
||||
- `linux-kernel.installTarget` has been removed, as it should not be necessary to customize.
|
||||
- `linux-kernel.DTB` is available as the `buildDTBs` parameter and passthru attribute on the kernel builders.
|
||||
- `linux-kernel.{autoModules,preferBuiltin,extraConfig}` were already available as kernel builder parameters.
|
||||
|
||||
- The ARMv5 Linux kernel build now uses a standard configuration and generates a standard compressed image instead of the deprecated legacy U‐Boot image format.
|
||||
`lib.systems.{examples,platforms}.{sheevaplug,pogoplug4}` have been unified into `lib.systems.examples.armv5tel-multiplatform`.
|
||||
Note that there is no official support for ARMv5 and it is not possible to build even a simple NixOS configuration out of the box.
|
||||
|
|
|
|||
|
|
@ -1018,38 +1018,16 @@ let
|
|||
mergedType = t.typeMerge t'.functor;
|
||||
typesMergeable = mergedType != null;
|
||||
|
||||
# TODO: Remove this when all downstream reliances of internals: 'functor.wrapped' are sufficiently migrated.
|
||||
# A function that adds the deprecated wrapped message to a type.
|
||||
addDeprecatedWrapped =
|
||||
t:
|
||||
t
|
||||
// {
|
||||
functor = t.functor // {
|
||||
wrapped = t.functor.wrappedDeprecationMessage {
|
||||
inherit loc;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
typeSet =
|
||||
if opt.options ? type then
|
||||
if res ? type then
|
||||
if typesMergeable then
|
||||
{
|
||||
type =
|
||||
if mergedType ? functor.wrappedDeprecationMessage then
|
||||
addDeprecatedWrapped mergedType
|
||||
else
|
||||
mergedType;
|
||||
}
|
||||
else
|
||||
# Keep in sync with the same error below!
|
||||
throw
|
||||
"The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
|
||||
else if opt.options.type ? functor.wrappedDeprecationMessage then
|
||||
{ type = addDeprecatedWrapped opt.options.type; }
|
||||
if opt.options ? type && res ? type then
|
||||
if typesMergeable then
|
||||
{
|
||||
type = mergedType;
|
||||
}
|
||||
else
|
||||
{ }
|
||||
# Keep in sync with the same error below!
|
||||
throw
|
||||
"The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
|
||||
else
|
||||
{ };
|
||||
|
||||
|
|
|
|||
|
|
@ -299,12 +299,10 @@ let
|
|||
inherit
|
||||
(
|
||||
{
|
||||
linux-kernel = args.linux-kernel or { };
|
||||
gcc = args.gcc or { };
|
||||
}
|
||||
// platforms.select final
|
||||
)
|
||||
linux-kernel
|
||||
gcc
|
||||
;
|
||||
|
||||
|
|
@ -692,6 +690,11 @@ let
|
|||
};
|
||||
};
|
||||
in
|
||||
# TODO: Remove in 27.05.
|
||||
assert
|
||||
args ? linux-kernel
|
||||
-> throw "lib.systems.elaborate: linux-kernel has been removed; see the 26.11 release notes";
|
||||
|
||||
assert final.useAndroidPrebuilt -> final.isAndroid;
|
||||
assert foldl' (pass: { assertion, message }: if assertion final then pass else throw message) true (
|
||||
final.parsed.abi.assertions or [ ]
|
||||
|
|
|
|||
|
|
@ -3,74 +3,21 @@
|
|||
# targetPlatform, etc) containing at least the minimal set of attrs
|
||||
# required (see types.parsedPlatform in lib/systems/parse.nix). This
|
||||
# file takes an already-valid platform and further elaborates it with
|
||||
# optional fields; currently these are: linux-kernel, gcc, and rustc.
|
||||
# optional fields; currently these are: gcc, and rustc.
|
||||
|
||||
{ lib }:
|
||||
rec {
|
||||
pc = {
|
||||
linux-kernel = {
|
||||
name = "pc";
|
||||
|
||||
baseConfig = "defconfig";
|
||||
# Build whatever possible as a module, if not stated in the extra config.
|
||||
autoModules = true;
|
||||
target = "bzImage";
|
||||
};
|
||||
};
|
||||
|
||||
##
|
||||
## POWER
|
||||
##
|
||||
|
||||
powernv = {
|
||||
linux-kernel = {
|
||||
name = "PowerNV";
|
||||
|
||||
baseConfig = "powernv_defconfig";
|
||||
target = "vmlinux";
|
||||
autoModules = true;
|
||||
};
|
||||
};
|
||||
|
||||
ppc64 = {
|
||||
linux-kernel = {
|
||||
name = "powerpc64";
|
||||
|
||||
baseConfig = "ppc64_defconfig";
|
||||
target = "vmlinux";
|
||||
autoModules = true;
|
||||
};
|
||||
};
|
||||
|
||||
##
|
||||
## ARM
|
||||
##
|
||||
|
||||
armv5tel-multiplatform = {
|
||||
linux-kernel = {
|
||||
name = "armv5tel-multiplatform";
|
||||
|
||||
baseConfig = "multi_v5_defconfig";
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
target = "zImage";
|
||||
};
|
||||
gcc = {
|
||||
arch = "armv5te";
|
||||
};
|
||||
};
|
||||
|
||||
raspberrypi = {
|
||||
linux-kernel = {
|
||||
name = "raspberrypi";
|
||||
|
||||
baseConfig = "bcm2835_defconfig";
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
target = "zImage";
|
||||
};
|
||||
gcc = {
|
||||
# https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications
|
||||
arch = "armv6kz";
|
||||
|
|
@ -105,7 +52,6 @@ rec {
|
|||
|
||||
# https://developer.android.com/ndk/guides/abis#v7a
|
||||
armv7a-android = {
|
||||
linux-kernel.name = "armeabi-v7a";
|
||||
gcc = {
|
||||
arch = "armv7-a";
|
||||
float-abi = "softfp";
|
||||
|
|
@ -114,14 +60,6 @@ rec {
|
|||
};
|
||||
|
||||
armv7l-hf-multiplatform = {
|
||||
linux-kernel = {
|
||||
name = "armv7l-hf-multiplatform";
|
||||
baseConfig = "defconfig";
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
target = "zImage";
|
||||
};
|
||||
gcc = {
|
||||
# Some table about fpu flags:
|
||||
# http://community.arm.com/servlet/JiveServlet/showImage/38-1981-3827/blogentry-103749-004812900+1365712953_thumb.png
|
||||
|
|
@ -146,19 +84,6 @@ rec {
|
|||
};
|
||||
|
||||
aarch64-multiplatform = {
|
||||
linux-kernel = {
|
||||
name = "aarch64-multiplatform";
|
||||
baseConfig = "defconfig";
|
||||
DTB = true;
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
extraConfig = ''
|
||||
# The default (=y) forces us to have the XHCI firmware available in initrd,
|
||||
# which our initrd builder can't currently do easily.
|
||||
USB_XHCI_TEGRA m
|
||||
'';
|
||||
target = "Image";
|
||||
};
|
||||
gcc = {
|
||||
arch = "armv8-a";
|
||||
};
|
||||
|
|
@ -176,9 +101,6 @@ rec {
|
|||
##
|
||||
|
||||
ben_nanonote = {
|
||||
linux-kernel = {
|
||||
name = "ben_nanonote";
|
||||
};
|
||||
gcc = {
|
||||
arch = "mips32";
|
||||
float = "soft";
|
||||
|
|
@ -235,17 +157,6 @@ rec {
|
|||
## Other
|
||||
##
|
||||
|
||||
riscv-multiplatform = {
|
||||
linux-kernel = {
|
||||
name = "riscv-multiplatform";
|
||||
target = "Image";
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
baseConfig = "defconfig";
|
||||
DTB = true;
|
||||
};
|
||||
};
|
||||
|
||||
loongarch64-multiplatform = {
|
||||
gcc = {
|
||||
# https://github.com/loongson/la-softdev-convention/blob/master/la-softdev-convention.adoc#10-operating-system-package-build-requirements
|
||||
|
|
@ -257,14 +168,6 @@ rec {
|
|||
# https://github.com/llvm/llvm-project/pull/132173
|
||||
cmodel = "medium";
|
||||
};
|
||||
linux-kernel = {
|
||||
name = "loongarch-multiplatform";
|
||||
target = "vmlinuz.efi";
|
||||
autoModules = true;
|
||||
preferBuiltin = true;
|
||||
baseConfig = "defconfig";
|
||||
DTB = true;
|
||||
};
|
||||
};
|
||||
|
||||
# This function takes a minimally-valid "platform" and returns an
|
||||
|
|
@ -272,17 +175,13 @@ rec {
|
|||
# included in the platform in order to further elaborate it.
|
||||
select =
|
||||
platform:
|
||||
# x86
|
||||
if platform.isx86 then
|
||||
pc
|
||||
|
||||
# ARM
|
||||
else if platform.isAarch32 then
|
||||
if platform.isAarch32 then
|
||||
let
|
||||
version = platform.parsed.cpu.version or null;
|
||||
in
|
||||
if version == null then
|
||||
pc
|
||||
{ }
|
||||
else if lib.versionOlder version "6" then
|
||||
armv5tel-multiplatform
|
||||
else if lib.versionOlder version "7" then
|
||||
|
|
@ -296,24 +195,9 @@ rec {
|
|||
else if platform.isLoongArch64 then
|
||||
loongarch64-multiplatform
|
||||
|
||||
else if platform.isRiscV then
|
||||
riscv-multiplatform
|
||||
|
||||
else if platform.parsed.cpu == lib.systems.parse.cpuTypes.mipsel then
|
||||
(import ./examples.nix { inherit lib; }).mipsel-linux-gnu
|
||||
|
||||
else if platform.isPower64 then
|
||||
if platform.isLittleEndian then powernv else ppc64
|
||||
|
||||
else if platform.isSh4 then
|
||||
{
|
||||
linux-kernel = {
|
||||
target = "vmlinux";
|
||||
# SH arch doesn't have a 'make install' target.
|
||||
installTarget = "vmlinux";
|
||||
};
|
||||
}
|
||||
|
||||
else
|
||||
{ };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,56 +515,6 @@ checkConfigError 'infinite recursion encountered' config.nonLazyResult ./lazy-at
|
|||
checkConfigOutput '^"mergedName.<id>.nested"$' config.result ./name-merge-attrsWith-1.nix
|
||||
checkConfigError 'The option .mergedName. in .*\.nix. is already declared in .*\.nix' config.mergedName ./name-merge-attrsWith-2.nix
|
||||
|
||||
# Test type.functor.wrapped deprecation warning
|
||||
# should emit the warning on:
|
||||
# - merged types
|
||||
# - non-merged types
|
||||
# - nestedTypes elemType
|
||||
# attrsWith
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.attrsWith.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedAttrsWith.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.attrsWith.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedAttrsWith.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
# listOf
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.listOf.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedListOf.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.listOf.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedListOf.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
# unique / uniq
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.unique.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedUnique.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.unique.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedUnique.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
# nullOr
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.nullOr.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedNullOr.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.nullOr.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedNullOr.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
# functionTo
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.functionTo.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedFunctionTo.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.functionTo.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedFunctionTo.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
# coercedTo
|
||||
# Note: test 'nestedTypes.finalType' and 'nestedTypes.coercedType'
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.nestedTypes.finalType.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.nestedTypes.coercedType.functor.wrapped ./deprecated-wrapped.nix
|
||||
# either
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.nestedTypes.left.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.nestedTypes.right.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.nestedTypes.left.functor.wrapped ./deprecated-wrapped.nix
|
||||
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.nestedTypes.right.functor.wrapped ./deprecated-wrapped.nix
|
||||
|
||||
# Even with multiple assignments, a type error should be thrown if any of them aren't valid
|
||||
checkConfigError 'A definition for option .* is not of type .*' \
|
||||
config.value ./declare-int-unsigned-value.nix ./define-value-list.nix ./define-value-int-positive.nix
|
||||
|
|
@ -733,9 +683,6 @@ checkConfigError 'The option .theOption.nested. in .other.nix. is already declar
|
|||
# Test that types.optionType leaves types untouched as long as they don't need to be merged
|
||||
checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survives-type-merge.nix
|
||||
|
||||
# Test that specifying both functor.wrapped and functor.payload isn't allowed
|
||||
checkConfigError 'Type foo defines both `functor.payload` and `functor.wrapped` at the same time, which is not supported.' config.result ./default-type-merge-both.nix
|
||||
|
||||
# Test that not including functor.wrapped is allowed
|
||||
checkConfigOutput 'ok' config.result ./default-type-merge-payload.nix
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
{ lib, options, ... }:
|
||||
let
|
||||
foo = lib.mkOptionType {
|
||||
name = "foo";
|
||||
functor = lib.types.defaultFunctor "foo" // {
|
||||
wrapped = lib.types.int;
|
||||
payload = 10;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = foo;
|
||||
};
|
||||
}
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = foo;
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
options.result = lib.mkOption {
|
||||
default = builtins.seq options.foo null;
|
||||
};
|
||||
}
|
||||
|
|
@ -99,7 +99,6 @@ let
|
|||
{ elemType, ... }@payload:
|
||||
{
|
||||
inherit name payload;
|
||||
wrappedDeprecationMessage = makeWrappedDeprecationMessage payload;
|
||||
type = types.${name};
|
||||
binOp =
|
||||
a: b:
|
||||
|
|
@ -108,14 +107,6 @@ let
|
|||
in
|
||||
if merged == null then null else { elemType = merged; };
|
||||
};
|
||||
makeWrappedDeprecationMessage =
|
||||
payload:
|
||||
{ loc }:
|
||||
lib.warn ''
|
||||
The deprecated `${lib.optionalString (loc != null) "type."}functor.wrapped` attribute ${
|
||||
lib.optionalString (loc != null) "of the option `${showOption loc}` "
|
||||
}is accessed, use `${lib.optionalString (loc != null) "type."}nestedTypes.elemType` instead.
|
||||
'' payload.elemType;
|
||||
|
||||
checkDefsForError =
|
||||
check: loc: defs:
|
||||
|
|
@ -168,21 +159,11 @@ rec {
|
|||
defaultTypeMerge =
|
||||
f: f':
|
||||
let
|
||||
mergedWrapped = f.wrapped.typeMerge f'.wrapped.functor;
|
||||
mergedPayload = f.binOp f.payload f'.payload;
|
||||
|
||||
hasPayload =
|
||||
assert (f'.payload != null) == (f.payload != null);
|
||||
f.payload != null;
|
||||
hasWrapped =
|
||||
let
|
||||
hasWrappedNonNull = set: set ? "wrapped" && set.wrapped != null;
|
||||
in
|
||||
assert (hasWrappedNonNull f') == (hasWrappedNonNull f);
|
||||
hasWrappedNonNull f;
|
||||
|
||||
typeFromPayload = if mergedPayload == null then null else f.type mergedPayload;
|
||||
typeFromWrapped = if mergedWrapped == null then null else f.type mergedWrapped;
|
||||
in
|
||||
# Abort early: cannot merge different types
|
||||
if f.name != f'.name then
|
||||
|
|
@ -190,22 +171,7 @@ rec {
|
|||
else
|
||||
|
||||
if hasPayload then
|
||||
# Just return the payload if returning wrapped is deprecated
|
||||
if f ? wrappedDeprecationMessage then
|
||||
typeFromPayload
|
||||
else if hasWrapped then
|
||||
# Has both wrapped and payload
|
||||
throw ''
|
||||
Type ${f.name} defines both `functor.payload` and `functor.wrapped` at the same time, which is not supported.
|
||||
|
||||
Use either `functor.payload` or `functor.wrapped` but not both.
|
||||
|
||||
If your code worked before remove either `functor.wrapped` or `functor.payload` from the type definition.
|
||||
''
|
||||
else
|
||||
typeFromPayload
|
||||
else if hasWrapped then
|
||||
typeFromWrapped
|
||||
if mergedPayload == null then null else f.type mergedPayload
|
||||
else
|
||||
f.type;
|
||||
|
||||
|
|
@ -213,7 +179,6 @@ rec {
|
|||
defaultFunctor = name: {
|
||||
inherit name;
|
||||
type = lib.types.${name} or null;
|
||||
wrapped = null;
|
||||
payload = null;
|
||||
binOp = a: b: null;
|
||||
};
|
||||
|
|
@ -309,17 +274,8 @@ rec {
|
|||
deprecationMessage
|
||||
nestedTypes
|
||||
descriptionClass
|
||||
functor
|
||||
;
|
||||
functor =
|
||||
if functor ? wrappedDeprecationMessage then
|
||||
functor
|
||||
// {
|
||||
wrapped = functor.wrappedDeprecationMessage {
|
||||
loc = null;
|
||||
};
|
||||
}
|
||||
else
|
||||
functor;
|
||||
description = if description == null then name else description;
|
||||
};
|
||||
|
||||
|
|
@ -1834,9 +1790,7 @@ rec {
|
|||
getSubModules = finalType.getSubModules;
|
||||
substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m);
|
||||
typeMerge = t: null;
|
||||
functor = (defaultFunctor name) // {
|
||||
wrappedDeprecationMessage = makeWrappedDeprecationMessage { elemType = finalType; };
|
||||
};
|
||||
functor = defaultFunctor name;
|
||||
nestedTypes.coercedType = coercedType;
|
||||
nestedTypes.finalType = finalType;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
"acme": {
|
||||
"description": "Maintain ACME-related packages and modules.",
|
||||
"id": 3806126,
|
||||
"maintainers": {},
|
||||
"maintainers": {
|
||||
"emilazy": 18535642
|
||||
},
|
||||
"members": {
|
||||
"arianvp": 628387,
|
||||
"emilazy": 18535642,
|
||||
"m1cr0man": 3044438
|
||||
},
|
||||
"name": "ACME"
|
||||
|
|
@ -71,11 +72,10 @@
|
|||
"description": "coordinates efforts towards bootstrappable builds (see https://bootstrappable.org/)",
|
||||
"id": 9141350,
|
||||
"maintainers": {
|
||||
"philiptaron": 43863,
|
||||
"zeuner": 2545850
|
||||
},
|
||||
"members": {
|
||||
"philiptaron": 43863
|
||||
},
|
||||
"members": {},
|
||||
"name": "bootstrapping"
|
||||
},
|
||||
"categorization": {
|
||||
|
|
@ -176,6 +176,7 @@
|
|||
"description": "Improve Darwin-support across Nixpkgs and help maintainers without access to Darwin hardware. Apply to join through https://github.com/NixOS/nixpkgs/issues/323144 to keep the process transparent.",
|
||||
"id": 2385202,
|
||||
"maintainers": {
|
||||
"emilazy": 18535642,
|
||||
"toonn": 1486805
|
||||
},
|
||||
"members": {
|
||||
|
|
@ -205,7 +206,6 @@
|
|||
"donn": 12652988,
|
||||
"dwt": 57199,
|
||||
"eclairevoyant": 848000,
|
||||
"emilazy": 18535642,
|
||||
"ethancedwards8": 60861925,
|
||||
"fiddlerwoaroof": 808745,
|
||||
"fulsomenko": 14945057,
|
||||
|
|
@ -410,9 +410,7 @@
|
|||
"jtojnar": 705123
|
||||
},
|
||||
"members": {
|
||||
"bobby285271": 20080233,
|
||||
"dasj19": 7589338,
|
||||
"hedning": 71978
|
||||
"bobby285271": 20080233
|
||||
},
|
||||
"name": "GNOME"
|
||||
},
|
||||
|
|
@ -556,11 +554,12 @@
|
|||
"id": 9955829,
|
||||
"maintainers": {
|
||||
"RossComputerGuy": 19699320,
|
||||
"alyssais": 2768870
|
||||
"alyssais": 2768870,
|
||||
"emilazy": 18535642
|
||||
},
|
||||
"members": {
|
||||
"Ericson2314": 1055245,
|
||||
"emilazy": 18535642,
|
||||
"peterwaller-arm": 52030119,
|
||||
"rrbutani": 7833358,
|
||||
"sternenseemann": 3154475
|
||||
},
|
||||
|
|
@ -695,8 +694,7 @@
|
|||
"description": "",
|
||||
"id": 174820,
|
||||
"maintainers": {
|
||||
"Ericson2314": 1055245,
|
||||
"tomberek": 178444
|
||||
"Ericson2314": 1055245
|
||||
},
|
||||
"members": {
|
||||
"Mic92": 96200,
|
||||
|
|
@ -704,6 +702,7 @@
|
|||
"edolstra": 1148549,
|
||||
"lisanna-dettwyler": 72424138,
|
||||
"lovesegfault": 7243783,
|
||||
"tomberek": 178444,
|
||||
"xokdvium": 145775305
|
||||
},
|
||||
"name": "Nix team"
|
||||
|
|
@ -852,15 +851,15 @@
|
|||
"description": "Team that is interested in reproducible builds",
|
||||
"id": 7625643,
|
||||
"maintainers": {
|
||||
"raboof": 131856,
|
||||
"zimbatm": 3248
|
||||
"raboof": 131856
|
||||
},
|
||||
"members": {
|
||||
"Artturin": 56650223,
|
||||
"Atemu": 18599032,
|
||||
"RaitoBezarius": 314564,
|
||||
"davidak": 91113,
|
||||
"mschwaig": 3856390
|
||||
"mschwaig": 3856390,
|
||||
"zimbatm": 3248
|
||||
},
|
||||
"name": "reproducible"
|
||||
},
|
||||
|
|
@ -964,13 +963,13 @@
|
|||
"description": "Maintain the standard environment and its surrounding logic.",
|
||||
"id": 11265412,
|
||||
"maintainers": {
|
||||
"RossComputerGuy": 19699320
|
||||
"RossComputerGuy": 19699320,
|
||||
"emilazy": 18535642,
|
||||
"philiptaron": 43863
|
||||
},
|
||||
"members": {
|
||||
"Artturin": 56650223,
|
||||
"Ericson2314": 1055245,
|
||||
"emilazy": 18535642,
|
||||
"philiptaron": 43863,
|
||||
"reckenrode": 7413633
|
||||
},
|
||||
"name": "stdenv"
|
||||
|
|
|
|||
|
|
@ -813,6 +813,13 @@
|
|||
githubId = 19290901;
|
||||
name = "Andrew Brooks";
|
||||
};
|
||||
agentelement = {
|
||||
email = "agentelement@agentelement.net";
|
||||
github = "agentelement";
|
||||
githubId = 38045210;
|
||||
name = "AgentElement";
|
||||
keys = [ { fingerprint = "D37E 581D AD71 2378 A622 5BC0 CD13 9E3B 4354 34F1"; } ];
|
||||
};
|
||||
agilesteel = {
|
||||
email = "agilesteel@gmail.com";
|
||||
github = "agilesteel";
|
||||
|
|
@ -2126,6 +2133,12 @@
|
|||
githubId = 56009;
|
||||
name = "Arcadio Rubio García";
|
||||
};
|
||||
arcayr = {
|
||||
email = "nixpkgs@arcayr.online";
|
||||
github = "arcayr";
|
||||
githubId = 11192354;
|
||||
name = "Elliot Speck";
|
||||
};
|
||||
archer-65 = {
|
||||
email = "mario.liguori.056@gmail.com";
|
||||
github = "archer-65";
|
||||
|
|
@ -2319,6 +2332,12 @@
|
|||
githubId = 3965744;
|
||||
name = "Arthur Lee";
|
||||
};
|
||||
arthurficial = {
|
||||
email = "arti.ficial@fullstackoptimization.com";
|
||||
github = "Arthur-Ficial";
|
||||
githubId = 258112064;
|
||||
name = "Arthur Ficial";
|
||||
};
|
||||
arthurteisseire = {
|
||||
email = "arthurteisseire33@gmail.com";
|
||||
github = "arthurteisseire";
|
||||
|
|
@ -6686,6 +6705,12 @@
|
|||
githubId = 90097;
|
||||
name = "Derek Collison";
|
||||
};
|
||||
DerGrumpf = {
|
||||
email = "phil.keier@hotmail.com";
|
||||
github = "DerGrumpf";
|
||||
githubId = 17272572;
|
||||
name = "Phil Keier";
|
||||
};
|
||||
DerGuteMoritz = {
|
||||
email = "moritz@twoticketsplease.de";
|
||||
github = "DerGuteMoritz";
|
||||
|
|
@ -7945,6 +7970,11 @@
|
|||
githubId = 18375468;
|
||||
name = "Elliot Xu";
|
||||
};
|
||||
elliotberman = {
|
||||
name = "Elliot Berman";
|
||||
github = "elliotberman";
|
||||
githubId = 210410075;
|
||||
};
|
||||
elliottslaughter = {
|
||||
name = "Elliott Slaughter";
|
||||
email = "elliottslaughter@gmail.com";
|
||||
|
|
@ -9639,6 +9669,11 @@
|
|||
githubId = 293586;
|
||||
name = "Adam Gamble";
|
||||
};
|
||||
gamebeaker = {
|
||||
github = "gamebeaker";
|
||||
githubId = 9269847;
|
||||
name = "gamebeaker";
|
||||
};
|
||||
gamedungeon = {
|
||||
github = "GameDungeon";
|
||||
githubId = 60719255;
|
||||
|
|
@ -10681,12 +10716,6 @@
|
|||
githubId = 2427959;
|
||||
name = "Hector Jusforgues";
|
||||
};
|
||||
hedning = {
|
||||
email = "torhedinbronner@gmail.com";
|
||||
github = "hedning";
|
||||
githubId = 71978;
|
||||
name = "Tor Hedin Brønner";
|
||||
};
|
||||
heel = {
|
||||
email = "parizhskiy@gmail.com";
|
||||
github = "HeeL";
|
||||
|
|
@ -10912,6 +10941,11 @@
|
|||
githubId = 58676303;
|
||||
name = "hhydraa";
|
||||
};
|
||||
hibiday = {
|
||||
name = "Katsumi Takeuchi";
|
||||
github = "hibiday";
|
||||
githubId = 137286929;
|
||||
};
|
||||
higebu = {
|
||||
name = "Yuya Kusakabe";
|
||||
email = "yuya.kusakabe@gmail.com";
|
||||
|
|
@ -12093,6 +12127,12 @@
|
|||
github = "Jaculabilis";
|
||||
githubId = 10787844;
|
||||
};
|
||||
jadewilk = {
|
||||
name = "Jade Wilk";
|
||||
email = "p.wilk@student.reading.ac.uk";
|
||||
github = "jadewilk";
|
||||
githubId = 50517631;
|
||||
};
|
||||
jaduff = {
|
||||
email = "jdduffpublic@proton.me";
|
||||
github = "jaduff";
|
||||
|
|
@ -13523,6 +13563,12 @@
|
|||
githubId = 5352661;
|
||||
name = "James Cleverley-Prance";
|
||||
};
|
||||
jpz13 = {
|
||||
email = "jp@pipekit.io";
|
||||
github = "JPZ13";
|
||||
githubId = 6625432;
|
||||
name = "J.P. Zivalich";
|
||||
};
|
||||
jqueiroz = {
|
||||
email = "nixos@johnjq.com";
|
||||
github = "jqueiroz";
|
||||
|
|
@ -21609,12 +21655,6 @@
|
|||
githubId = 43863;
|
||||
name = "Philip Taron";
|
||||
};
|
||||
philipwilk = {
|
||||
name = "Philip Wilk";
|
||||
email = "p.wilk@student.reading.ac.uk";
|
||||
github = "philipwilk";
|
||||
githubId = 50517631;
|
||||
};
|
||||
philocalyst = {
|
||||
name = "Myles Wirth";
|
||||
email = "milestheperson@posteo.net";
|
||||
|
|
@ -23342,6 +23382,11 @@
|
|||
github = "Reputable2772";
|
||||
githubId = 153411261;
|
||||
};
|
||||
ReStranger = {
|
||||
name = "ReStranger";
|
||||
github = "ReStranger";
|
||||
githubId = 69393944;
|
||||
};
|
||||
ret2pop = {
|
||||
email = "ret2pop@gmail.com";
|
||||
github = "ret2pop";
|
||||
|
|
@ -27034,6 +27079,12 @@
|
|||
githubId = 6064962;
|
||||
name = "TakWolf";
|
||||
};
|
||||
talal = {
|
||||
email = "noreply@talal.ch";
|
||||
github = "talal";
|
||||
githubId = 3526562;
|
||||
name = "Muhammad Talal Anwar";
|
||||
};
|
||||
talhaHavadar = {
|
||||
email = "havadartalha@gmail.com";
|
||||
github = "talhaHavadar";
|
||||
|
|
@ -30150,6 +30201,12 @@
|
|||
githubId = 36407913;
|
||||
name = "Uli Baum";
|
||||
};
|
||||
xelacodes = {
|
||||
name = "Alex";
|
||||
github = "itzTheMeow";
|
||||
githubId = 50887230;
|
||||
email = "nixpkgs@xela.codes";
|
||||
};
|
||||
xelden = {
|
||||
email = "anpiz@protonmail.com";
|
||||
github = "Xelden";
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ cassowary,,,,,,alerque
|
|||
cldr,,,,,,alerque
|
||||
commons.nvim,,,,,5.1,mrcjkb
|
||||
compat53,,,,,,vcunat
|
||||
coop.nvim,,,,,,
|
||||
cosmo,,,,,,
|
||||
coxpcall,,,,1.17.0-1,,
|
||||
cqueues,,,,,,vcunat
|
||||
|
|
@ -53,8 +54,8 @@ lrexlib-pcre2,,,,,,wishstudio
|
|||
lrexlib-posix,,,,,,
|
||||
lsp-progress.nvim,,,,,5.1,gepbird
|
||||
lsqlite3,,,,,,
|
||||
ltreesitter-ts,,,,,,
|
||||
ltreesitter,,,,,,
|
||||
ltreesitter-ts,,,,,,
|
||||
lua-cjson,,,,,,
|
||||
lua-cmsgpack,,,,,,
|
||||
lua-curl,,,,,,
|
||||
|
|
@ -174,8 +175,8 @@ tree-sitter-http,,,,0.0.33-1,,
|
|||
tree-sitter-norg,,,,,5.1,mrcjkb
|
||||
tree-sitter-norg-meta,,,,,,
|
||||
tree-sitter-orgmode,,,,,5.1,
|
||||
utf8,,,,,,
|
||||
tree-sitter-teal,,,,,,
|
||||
utf8,,,,,,
|
||||
vicious,,,,,,
|
||||
vstruct,,,,,,
|
||||
vusted,,,,,,
|
||||
|
|
|
|||
|
|
|
@ -130,6 +130,8 @@
|
|||
|
||||
- [linkding](https://linkding.link/), a self-hosted bookmark manager designed to be minimal, fast, and easy to set up. Available as [services.linkding](#opt-services.linkding.enable).
|
||||
|
||||
- [gs1200-exporter](https://github.com/robinelfrink/gs1200-exporter), a Prometheus exporter for Zyxel GS1200 series switches. Available as [services.gs1200-exporter](#opt-services.gs1200-exporter.enable).
|
||||
|
||||
- [Tinyauth](https://tinyauth.app/), a simple authentication middleware for web apps, with OAuth and LDAP support. Available as [services.tinyauth](#opt-services.tinyauth.enable).
|
||||
|
||||
- [Strichliste](https://www.strichliste.org), a digital self-service tallysheet used in hackerspaces, clubs and offices. Available as [services.strichliste](#opt-services.strichliste.enable).
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
- [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).
|
||||
|
||||
- [scx_loader](https://github.com/sched-ext/scx-loader), a system daemon and DBus-based loader for sched_ext schedulers. `scxctl` is the command-line client for interacting with the loader, allowing users to switch schedulers, modes, and arguments dynamically. Available as [services.scx-loader](#opt-services.scx-loader.enable)
|
||||
|
||||
- [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).
|
||||
|
||||
## Backward Incompatibilities {#sec-release-26.11-incompatibilities}
|
||||
|
|
@ -22,10 +24,16 @@
|
|||
|
||||
- Support for the legacy U‐Boot image format has been removed from the initrd generators, as it is deprecated upstream and no longer used by any platform in Nixpkgs.
|
||||
|
||||
- `services.llama-cpp` is now configured using structured `services.llama-cpp.settings` attribute.
|
||||
|
||||
- Python 2 has been removed from the top-level package set, as it is long past end-of-life. The `python2`, `python27`, `python2Full`, `python27Full`, `python2Packages`, and `python27Packages` attributes, along with the legacy `python`, `pythonFull`, and `pythonPackages` aliases, now throw an error directing you to `python3`. The `isPy2` and `isPy27` package flags have been removed accordingly. The only remaining Python 2 interpreter is vendored inside the `resholve` package for its `oil` dependency and is not exposed for general use.
|
||||
|
||||
- `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;`.
|
||||
|
||||
- `services.timesyncd.extraConfig` has been removed in favor of the structured [](#opt-services.timesyncd.settings.Time) option. Use `services.timesyncd.settings.Time` to set any `timesyncd.conf(5)` option directly. For example, replace `services.timesyncd.extraConfig = "PollIntervalMaxSec=180";` with `services.timesyncd.settings.Time.PollIntervalMaxSec = 180;`.
|
||||
|
||||
- `services.firezone.server.provision` has been removed due to it being unmaintanable. Remove all uses of provisioning and use the WebUI to configure firezone.
|
||||
|
||||
## Other Notable Changes {#sec-release-26.11-notable-changes}
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ let
|
|||
|
||||
inherit (config) sshBackdoor;
|
||||
|
||||
inherit (hostPkgs.stdenv.hostPlatform) isLinux;
|
||||
inherit (hostPkgs.stdenv.hostPlatform) isLinux isAarch64;
|
||||
|
||||
# Reifies and correctly wraps the python test driver for
|
||||
# the respective qemu version and with or without ocr support
|
||||
|
|
@ -256,6 +256,10 @@ in
|
|||
#
|
||||
# If needed, this can still be turned off.
|
||||
virtualisation.qemu.enableSharedMemory = lib.mkDefault isLinux;
|
||||
# Needed for screenshots to work (in e.g `nixosTests.login`)
|
||||
virtualisation.qemu.options = lib.optionals (isLinux && isAarch64) [
|
||||
"-device virtio-gpu-pci"
|
||||
];
|
||||
|
||||
assertions = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -950,32 +950,8 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
# Warn about user accounts with deprecated password hashing schemes
|
||||
# This does not work when the users and groups are created by
|
||||
# systemd-sysusers because the users are created too late then.
|
||||
system.activationScripts.hashes =
|
||||
if !config.systemd.sysusers.enable && !config.services.userborn.enable then
|
||||
{
|
||||
deps = [ "users" ];
|
||||
text = ''
|
||||
users=()
|
||||
while IFS=: read -r user hash _; do
|
||||
if [[ "$hash" = "$"* && ! "$hash" =~ ^\''$${cryptSchemeIdPatternGroup}\$ ]]; then
|
||||
users+=("$user")
|
||||
fi
|
||||
done </etc/shadow
|
||||
|
||||
if (( "''${#users[@]}" )); then
|
||||
echo "
|
||||
WARNING: The following user accounts rely on password hashing algorithms
|
||||
that have been removed. They need to be renewed as soon as possible, as
|
||||
they do prevent their users from logging in."
|
||||
printf ' - %s\n' "''${users[@]}"
|
||||
fi
|
||||
'';
|
||||
}
|
||||
else
|
||||
""; # keep around for backwards compatibility
|
||||
# for backwards compatibility
|
||||
system.activationScripts.hashes = stringAfter [ "users" ] "";
|
||||
|
||||
# for backwards compatibility
|
||||
system.activationScripts.groups = stringAfter [ "users" ] "";
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ in
|
|||
options = {
|
||||
hardware.deviceTree = {
|
||||
enable = lib.mkOption {
|
||||
default = pkgs.stdenv.hostPlatform.linux-kernel.DTB or false;
|
||||
default = config.boot.kernelPackages.kernel.buildDTBs;
|
||||
defaultText = lib.literalExpression "config.boot.kernelPackages.kernel.buildDTBs";
|
||||
type = lib.types.bool;
|
||||
description = ''
|
||||
Build device tree files. These are used to describe the
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ with lib;
|
|||
#!ipxe
|
||||
# Use the cmdline variable to allow the user to specify custom kernel params
|
||||
# when chainloading this script from other iPXE scripts like netboot.xyz
|
||||
kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} ''${cmdline}
|
||||
kernel ${config.boot.kernelPackages.kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} ''${cmdline}
|
||||
initrd initrd
|
||||
boot
|
||||
'';
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@
|
|||
./programs/iio-hyprland.nix
|
||||
./programs/immersed.nix
|
||||
./programs/iotop.nix
|
||||
./programs/jai-jail.nix
|
||||
./programs/java.nix
|
||||
./programs/joycond-cemuhook.nix
|
||||
./programs/k3b.nix
|
||||
|
|
@ -1033,6 +1034,7 @@
|
|||
./services/monitoring/grafana-to-ntfy.nix
|
||||
./services/monitoring/grafana.nix
|
||||
./services/monitoring/graphite.nix
|
||||
./services/monitoring/gs1200-exporter.nix
|
||||
./services/monitoring/hdaps.nix
|
||||
./services/monitoring/heapster.nix
|
||||
./services/monitoring/incron.nix
|
||||
|
|
@ -1485,6 +1487,7 @@
|
|||
./services/scheduling/cron.nix
|
||||
./services/scheduling/fcron.nix
|
||||
./services/scheduling/prefect.nix
|
||||
./services/scheduling/scx-loader.nix
|
||||
./services/scheduling/scx.nix
|
||||
./services/search/elasticsearch-curator.nix
|
||||
./services/search/elasticsearch.nix
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
RuntimeDirectory = "clash-verge-rev";
|
||||
StateDirectory = "clash-verge-service";
|
||||
ProtectClock = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictSUIDSGID = true;
|
||||
|
|
|
|||
|
|
@ -9,14 +9,11 @@ function chpwd-osc7-pwd() {
|
|||
(( ZSH_SUBSHELL )) || osc7-pwd
|
||||
}
|
||||
|
||||
precmd() {
|
||||
print -Pn "\e]133;A\e\\"
|
||||
}
|
||||
|
||||
function precmd {
|
||||
if ! builtin zle; then
|
||||
print -n "\e]133;D\e\\"
|
||||
fi
|
||||
print -Pn "\e]133;A\e\\"
|
||||
}
|
||||
|
||||
function preexec {
|
||||
|
|
|
|||
45
nixos/modules/programs/jai-jail.nix
Normal file
45
nixos/modules/programs/jai-jail.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.programs.jai-jail;
|
||||
|
||||
in
|
||||
{
|
||||
options.programs.jai-jail = {
|
||||
enable = lib.mkEnableOption "jai, a sandbox for AI agents";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = pkgs.jai-jail;
|
||||
defaultText = lib.literalExpression "pkgs.jai-jail";
|
||||
description = "The jai package to use.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
security.wrappers.jai = {
|
||||
setuid = true;
|
||||
owner = "root";
|
||||
group = "root";
|
||||
source = "${cfg.package}/bin/jai";
|
||||
};
|
||||
|
||||
users.users.jai = {
|
||||
isSystemUser = true;
|
||||
group = "jai";
|
||||
home = "/";
|
||||
description = "JAI sandbox untrusted user";
|
||||
};
|
||||
|
||||
users.groups.jai = { };
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ agentelement ];
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ in
|
|||
only the hosts listed in {var}`dataDir`/remote_hosts.cfg will be allowed to
|
||||
connect.
|
||||
|
||||
See also: <https://boinc.berkeley.edu/wiki/Controlling_BOINC_remotely#Remote_access>
|
||||
See also: <https://github.com/BOINC/boinc/wiki/Controlling_BOINC_remotely#remote-access>
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ in
|
|||
package = lib.mkPackageOption pkgs "espanso" {
|
||||
example = "pkgs.espanso-wayland";
|
||||
};
|
||||
extraPackages = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
default = [ ];
|
||||
example = lib.literalExpression "with pkgs; [ bash curl python3 ];";
|
||||
description = "Extra packages to be added to Espanso service path.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -43,6 +49,7 @@ in
|
|||
Restart = "on-failure";
|
||||
};
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
path = cfg.extraPackages;
|
||||
};
|
||||
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ philipwilk ];
|
||||
meta.maintainers = with lib.maintainers; [ jadewilk ];
|
||||
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ in
|
|||
};
|
||||
users.groups.scanservjs = { };
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.stateDir}/data 0755 scanservjs scanservjs - -"
|
||||
"d ${cfg.stateDir}/data/preview 0755 scanservjs scanservjs - -"
|
||||
"L+ ${cfg.stateDir}/data/preview/default.jpg - - - - ${package}/lib/data/preview/default.jpg"
|
||||
];
|
||||
|
||||
systemd.services.scanservjs = {
|
||||
description = "scanservjs";
|
||||
after = [ "network.target" ];
|
||||
|
|
|
|||
|
|
@ -864,12 +864,19 @@ in
|
|||
|
||||
networking.firewall.allowedTCPPorts = mkMerge [
|
||||
(mkIf cfg.openFirewall [ cfg.config.http.server_port ])
|
||||
(mkIf cfg.openFirewallForComponents
|
||||
(mkIf cfg.openFirewallForComponents (
|
||||
# https://www.home-assistant.io/integrations/homekit/#firewall
|
||||
optionals (useComponent "homekit") [ 21063 ]
|
||||
# https://www.home-assistant.io/integrations/sonos/#network-requirements
|
||||
(optionals (useComponent "sonos") [ 1400 ])
|
||||
)
|
||||
++ optionals (useComponent "sonos") [ 1400 ]
|
||||
))
|
||||
];
|
||||
|
||||
networking.firewall.allowedUDPPorts = mkIf cfg.openFirewallForComponents (
|
||||
# https://www.home-assistant.io/integrations/homekit/#firewall
|
||||
optionals (useComponent "homekit") [ 5353 ]
|
||||
);
|
||||
|
||||
# symlink the configuration to /etc/home-assistant
|
||||
environment.etc = mkMerge [
|
||||
(mkIf (cfg.config != null && !cfg.configWritable) {
|
||||
|
|
|
|||
|
|
@ -304,7 +304,6 @@ in
|
|||
meta = {
|
||||
maintainers = with lib.maintainers; [
|
||||
happysalada
|
||||
euxane
|
||||
onny
|
||||
norpol
|
||||
];
|
||||
|
|
|
|||
|
|
@ -32,9 +32,14 @@ let
|
|||
);
|
||||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
|
||||
functor = (lib.defaultFunctor name) // {
|
||||
wrapped = elemType;
|
||||
};
|
||||
functor = (
|
||||
lib.types.elemTypeFunctor "attrsWith" {
|
||||
inherit
|
||||
elemType
|
||||
name
|
||||
;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
profileModule = lib.types.submodule {
|
||||
|
|
|
|||
|
|
@ -252,12 +252,13 @@ in
|
|||
in
|
||||
{
|
||||
"/" = {
|
||||
# recommendedProxySettings sets the standard headers (Host, X-Forwarded-*), so
|
||||
# don't also set them via proxy_set_header in extraConfig below. Nginx would then
|
||||
# send Host twice and Django rejects it with DisallowedHost. Enabled per-location
|
||||
# so it works even if the host's global recommendedProxySettings is off.
|
||||
recommendedProxySettings = true;
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header CLIENT_IP $remote_addr;
|
||||
|
||||
proxy_pass_request_headers on;
|
||||
|
|
@ -272,6 +273,8 @@ in
|
|||
proxyPass = "http://unix:${unixPath}";
|
||||
};
|
||||
"/auth" = {
|
||||
# same reasoning as "/"; this subrequest also reaches Django
|
||||
recommendedProxySettings = true;
|
||||
extraConfig = ''
|
||||
internal;
|
||||
proxy_pass_request_body off;
|
||||
|
|
|
|||
|
|
@ -2,188 +2,173 @@
|
|||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.llama-cpp;
|
||||
|
||||
modelsPresetFile =
|
||||
if cfg.modelsPreset != null then
|
||||
pkgs.writeText "llama-models.ini" (lib.generators.toINI { } cfg.modelsPreset)
|
||||
else
|
||||
null;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "llama-cpp" "host" ]
|
||||
[ "services" "llama-cpp" "settings" "host" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "llama-cpp" "port" ]
|
||||
[ "services" "llama-cpp" "settings" "port" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "llama-cpp" "model" ]
|
||||
[ "services" "llama-cpp" "settings" "model" ]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "llama-cpp" "modelsDir" ]
|
||||
[ "services" "llama-cpp" "settings" "models-dir" ]
|
||||
)
|
||||
(lib.mkRemovedOptionModule [ "services" "llama-cpp" "modelsPreset" ] ''
|
||||
Using a Nix attribute set for configuring model presets is no longer
|
||||
supported. However, it's possible to use
|
||||
`services.llama-cpp.settings.models-preset` to provide a path to an INI
|
||||
file with desired options.
|
||||
'')
|
||||
(lib.mkRemovedOptionModule [
|
||||
"services"
|
||||
"llama-cpp"
|
||||
"extraFlags"
|
||||
] "Use `services.llama-cpp.settings` instead")
|
||||
];
|
||||
|
||||
options = {
|
||||
|
||||
services.llama-cpp = {
|
||||
enable = lib.mkEnableOption "LLaMA C++ server";
|
||||
enable = lib.mkEnableOption "llama.cpp HTTP server";
|
||||
|
||||
package = lib.mkPackageOption pkgs "llama-cpp" { };
|
||||
|
||||
model = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
example = "/models/mistral-instruct-7b/ggml-model-q4_0.gguf";
|
||||
description = "Model path.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
modelsDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
example = "/models/";
|
||||
description = "Models directory.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
modelsPreset = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.attrsOf lib.types.attrs);
|
||||
default = null;
|
||||
description = ''
|
||||
Models preset configuration as a Nix attribute set.
|
||||
This is converted to an INI file and passed to llama-server via --model-preset.
|
||||
See llama-server documentation for available options.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"Qwen3-Coder-Next" = {
|
||||
hf-repo = "unsloth/Qwen3-Coder-Next-GGUF";
|
||||
hf-file = "Qwen3-Coder-Next-UD-Q4_K_XL.gguf";
|
||||
alias = "unsloth/Qwen3-Coder-Next";
|
||||
fit = "on";
|
||||
seed = "3407";
|
||||
temp = "1.0";
|
||||
top-p = "0.95";
|
||||
min-p = "0.01";
|
||||
top-k = "40";
|
||||
jinja = "on";
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.attrs;
|
||||
options = {
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "127.0.0.1";
|
||||
example = "0.0.0.0";
|
||||
description = ''
|
||||
IP address on which the server should listen on.
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8080;
|
||||
example = 1337;
|
||||
description = ''
|
||||
Port on which the server should listen on.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
example = {
|
||||
host = "0.0.0.0";
|
||||
port = 1337;
|
||||
model = "/mnt/llms/Foo3.6-27B-UD-Q4_K_XL.gguf";
|
||||
ctx-size = 252144;
|
||||
temp = 0.6;
|
||||
top-k = 20;
|
||||
top-p = 0.95;
|
||||
batch-size = 512;
|
||||
ubatch-size = 256;
|
||||
spec-type = "draft-mtp";
|
||||
spec-draft-n-max = 2;
|
||||
flash-attn = "on";
|
||||
};
|
||||
description = ''
|
||||
Command-line arguments for `llama-server`.
|
||||
|
||||
See <https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md>
|
||||
for the full list of options.
|
||||
'';
|
||||
};
|
||||
|
||||
extraFlags = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Extra flags passed to llama-cpp-server.";
|
||||
example = [
|
||||
"-c"
|
||||
"4096"
|
||||
"-ngl"
|
||||
"32"
|
||||
"--numa"
|
||||
"numactl"
|
||||
];
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "127.0.0.1";
|
||||
example = "0.0.0.0";
|
||||
description = "IP address the LLaMA C++ server listens on.";
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8080;
|
||||
description = "Listen port for LLaMA C++ server.";
|
||||
};
|
||||
|
||||
openFirewall = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Open ports in the firewall for LLaMA C++ server.";
|
||||
description = ''
|
||||
Open ports in the firewall for the server.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.llama-cpp = {
|
||||
description = "LLaMA C++ server";
|
||||
description = "llama.cpp HTTP server";
|
||||
wants = [ "network.target" ];
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "idle";
|
||||
KillSignal = "SIGINT";
|
||||
ExecStart = toString [
|
||||
(lib.getExe' cfg.package "llama-server")
|
||||
(lib.cli.toCommandLine (optionName: {
|
||||
option = if builtins.stringLength optionName > 1 then "--${optionName}" else "-${optionName}";
|
||||
sep = " ";
|
||||
explicitBool = false;
|
||||
formatArg = lib.generators.mkValueStringDefault { };
|
||||
}) cfg.settings)
|
||||
];
|
||||
ExecReload = "${lib.getExe' pkgs.coreutils "kill"} -HUP $MAINPID";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 300;
|
||||
|
||||
DynamicUser = true;
|
||||
StateDirectory = "llama-cpp";
|
||||
CacheDirectory = "llama-cpp";
|
||||
WorkingDirectory = "/var/lib/llama-cpp";
|
||||
Environment = [ "LLAMA_CACHE=/var/cache/llama-cpp" ];
|
||||
ExecStart =
|
||||
let
|
||||
args = [
|
||||
"--host"
|
||||
cfg.host
|
||||
"--port"
|
||||
(toString cfg.port)
|
||||
]
|
||||
++ lib.optionals (cfg.model != null) [
|
||||
"-m"
|
||||
cfg.model
|
||||
]
|
||||
++ lib.optionals (cfg.modelsDir != null) [
|
||||
"--models-dir"
|
||||
cfg.modelsDir
|
||||
]
|
||||
++ lib.optionals (cfg.modelsPreset != null) [
|
||||
"--models-preset"
|
||||
modelsPresetFile
|
||||
]
|
||||
++ cfg.extraFlags;
|
||||
in
|
||||
"${cfg.package}/bin/llama-server ${utils.escapeSystemdExecArgs args}";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 300;
|
||||
|
||||
# for GPU acceleration
|
||||
PrivateDevices = false;
|
||||
|
||||
# hardening
|
||||
DynamicUser = true;
|
||||
CapabilityBoundingSet = "";
|
||||
AmbientCapabilities = [ "" ];
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = false; # Required for GPU support.
|
||||
PrivateMounts = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RemoveIPC = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
NoNewPrivileges = true;
|
||||
PrivateMounts = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectSystem = "strict";
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
RemoveIPC = true;
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
ProtectProc = "invisible";
|
||||
ProtectHostname = true;
|
||||
ProcSubset = "pid";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.optional cfg.openFirewall cfg.port;
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ newam ];
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
azahi
|
||||
newam
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,5 +146,5 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ euxane ];
|
||||
meta.maintainers = with lib.maintainers; [ martinetd ];
|
||||
}
|
||||
|
|
|
|||
95
nixos/modules/services/monitoring/gs1200-exporter.nix
Normal file
95
nixos/modules/services/monitoring/gs1200-exporter.nix
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.gs1200-exporter;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ DerGrumpf ];
|
||||
|
||||
options.services.gs1200-exporter = {
|
||||
enable = lib.mkEnableOption "gs1200-exporter";
|
||||
|
||||
address = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "IP address or hostname of the GS1200 switch.";
|
||||
example = "192.168.1.3";
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 9934;
|
||||
description = "Port on which to expose Prometheus metrics.";
|
||||
};
|
||||
|
||||
passwordFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a file containing the password to log in to the GS1200 web interface.
|
||||
This is the recommended option as it avoids storing the password in the Nix store.
|
||||
Compatible with sops-nix and agenix.
|
||||
'';
|
||||
example = "/run/secrets/gs1200-password";
|
||||
};
|
||||
|
||||
debug = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable debug logging. Logs are accessible via journalctl -u gs1200-exporter.";
|
||||
};
|
||||
|
||||
verbose = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable verbose logging. Logs are accessible via journalctl -u gs1200-exporter.";
|
||||
};
|
||||
|
||||
json = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Output logs in JSON format. Logs are accessible via journalctl -u gs1200-exporter.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
systemd.services.gs1200-exporter = {
|
||||
description = "Prometheus exporter for Zyxel GS1200 switches";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
Restart = "always";
|
||||
|
||||
# Hardening
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
CapabilityBoundingSet = "";
|
||||
};
|
||||
|
||||
script =
|
||||
let
|
||||
args = lib.concatStringsSep " " (
|
||||
[
|
||||
"--address ${cfg.address}"
|
||||
"--port ${toString cfg.port}"
|
||||
]
|
||||
++ lib.optional cfg.debug "--debug"
|
||||
++ lib.optional cfg.verbose "--verbose"
|
||||
++ lib.optional cfg.json "--json"
|
||||
);
|
||||
in
|
||||
''
|
||||
export GS1200_PASSWORD=$(cat ${cfg.passwordFile})
|
||||
exec ${lib.getExe pkgs.gs1200-exporter} ${args}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,709 +0,0 @@
|
|||
defmodule Provision do
|
||||
alias Domain.{Repo, Accounts, Auth, Actors, Resources, Tokens, Gateways, Relays, Policies}
|
||||
require Logger
|
||||
|
||||
# UUID Mapping handling
|
||||
defmodule UuidMapping do
|
||||
@mapping_file "provision-uuids.json"
|
||||
|
||||
# Loads the mapping from file
|
||||
def load do
|
||||
mappings = case File.read(@mapping_file) do
|
||||
{:ok, content} ->
|
||||
case Jason.decode(content) do
|
||||
{:ok, mapping} -> mapping
|
||||
_ -> %{"accounts" => %{}}
|
||||
end
|
||||
|
||||
_ -> %{"accounts" => %{}}
|
||||
end
|
||||
Process.put(:uuid_mappings, mappings)
|
||||
mappings
|
||||
end
|
||||
|
||||
# Saves the current mapping (defaulting to the one in the process dictionary)
|
||||
def save(mapping \\ Process.get(:uuid_mappings)) do
|
||||
File.write!(@mapping_file, Jason.encode!(mapping))
|
||||
end
|
||||
|
||||
# Retrieves the account-level mapping from a given mapping (or from Process)
|
||||
def get_account(mapping \\ Process.get(:uuid_mappings), account_slug) do
|
||||
get_in(mapping, ["accounts", account_slug]) || %{}
|
||||
end
|
||||
|
||||
# Retrieves the entity mapping for a specific account and type
|
||||
def get_entities(mapping \\ Process.get(:uuid_mappings), account_slug, type) do
|
||||
get_in(mapping, ["accounts", account_slug, type]) || %{}
|
||||
end
|
||||
|
||||
# Retrieves an entity mapping for a specific account, type and external_id
|
||||
def get_entity(mapping \\ Process.get(:uuid_mappings), account_slug, type, external_id) do
|
||||
get_in(mapping, ["accounts", account_slug, type, external_id])
|
||||
end
|
||||
|
||||
# Updates (or creates) the account UUID mapping and stores it in the process dictionary.
|
||||
def update_account(account_slug, uuid) do
|
||||
mapping = Process.get(:uuid_mappings) || load()
|
||||
mapping = ensure_account_exists(mapping, account_slug)
|
||||
mapping = put_in(mapping, ["accounts", account_slug, "id"], uuid)
|
||||
Process.put(:uuid_mappings, mapping)
|
||||
mapping
|
||||
end
|
||||
|
||||
# Ensures that the given account exists in the mapping.
|
||||
def ensure_account_exists(mapping, account_slug) do
|
||||
if not Map.has_key?(mapping["accounts"], account_slug) do
|
||||
put_in(mapping, ["accounts", account_slug], %{})
|
||||
else
|
||||
mapping
|
||||
end
|
||||
end
|
||||
|
||||
# Updates (or creates) the mapping for entities of a given type for the account.
|
||||
def update_entities(account_slug, type, new_entries) do
|
||||
mapping = Process.get(:uuid_mappings) || load()
|
||||
mapping = ensure_account_exists(mapping, account_slug)
|
||||
current = get_entities(mapping, account_slug, type)
|
||||
mapping = put_in(mapping, ["accounts", account_slug, type], Map.merge(current, new_entries))
|
||||
Process.put(:uuid_mappings, mapping)
|
||||
mapping
|
||||
end
|
||||
|
||||
# Removes an entire account from the mapping.
|
||||
def remove_account(account_slug) do
|
||||
mapping = Process.get(:uuid_mappings) || load()
|
||||
mapping = update_in(mapping, ["accounts"], fn accounts ->
|
||||
Map.delete(accounts, account_slug)
|
||||
end)
|
||||
Process.put(:uuid_mappings, mapping)
|
||||
mapping
|
||||
end
|
||||
|
||||
# Removes a specific entity mapping for the account.
|
||||
def remove_entity(account_slug, type, key) do
|
||||
mapping = Process.get(:uuid_mappings) || load()
|
||||
mapping = update_in(mapping, ["accounts", account_slug, type], fn entities ->
|
||||
Map.delete(entities || %{}, key)
|
||||
end)
|
||||
Process.put(:uuid_mappings, mapping)
|
||||
mapping
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_references(value) when is_map(value) do
|
||||
Enum.into(value, %{}, fn {k, v} -> {k, resolve_references(v)} end)
|
||||
end
|
||||
|
||||
defp resolve_references(value) when is_list(value) do
|
||||
Enum.map(value, &resolve_references/1)
|
||||
end
|
||||
|
||||
defp resolve_references(value) when is_binary(value) do
|
||||
Regex.replace(~r/\{env:([^}]+)\}/, value, fn _, var ->
|
||||
System.get_env(var) || raise "Environment variable #{var} not set"
|
||||
end)
|
||||
end
|
||||
|
||||
defp resolve_references(value), do: value
|
||||
|
||||
defp atomize_keys(map) when is_map(map) do
|
||||
Enum.into(map, %{}, fn {k, v} ->
|
||||
{
|
||||
if(is_binary(k), do: String.to_atom(k), else: k),
|
||||
if(is_map(v), do: atomize_keys(v), else: v)
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp cleanup_account(uuid) do
|
||||
case Accounts.fetch_account_by_id_or_slug(uuid) do
|
||||
{:ok, value} when value.deleted_at == nil ->
|
||||
Logger.info("Deleting removed account #{value.slug}")
|
||||
value |> Ecto.Changeset.change(%{ deleted_at: DateTime.utc_now() }) |> Repo.update!()
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_actor(uuid, subject) do
|
||||
case Actors.fetch_actor_by_id(uuid, subject) do
|
||||
{:ok, value} ->
|
||||
Logger.info("Deleting removed actor #{value.name}")
|
||||
{:ok, _} = Actors.delete_actor(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_provider(uuid, subject) do
|
||||
case Auth.fetch_provider_by_id(uuid, subject) do
|
||||
{:ok, value} ->
|
||||
Logger.info("Deleting removed provider #{value.name}")
|
||||
{:ok, _} = Auth.delete_provider(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_gateway_group(uuid, subject) do
|
||||
case Gateways.fetch_group_by_id(uuid, subject) do
|
||||
{:ok, value} ->
|
||||
Logger.info("Deleting removed gateway group #{value.name}")
|
||||
{:ok, _} = Gateways.delete_group(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_relay_group(uuid, subject) do
|
||||
case Relays.fetch_group_by_id(uuid, subject) do
|
||||
{:ok, value} ->
|
||||
Logger.info("Deleting removed relay group #{value.name}")
|
||||
{:ok, _} = Relays.delete_group(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_actor_group(uuid, subject) do
|
||||
case Actors.fetch_group_by_id(uuid, subject) do
|
||||
{:ok, value} ->
|
||||
Logger.info("Deleting removed actor group #{value.name}")
|
||||
{:ok, _} = Actors.delete_group(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
# Fetch resource by uuid, but follow the chain of replacements if any
|
||||
defp fetch_resource(uuid, subject) do
|
||||
case Resources.fetch_resource_by_id(uuid, subject) do
|
||||
{:ok, resource} when resource.replaced_by_resource_id != nil -> fetch_resource(resource.replaced_by_resource_id, subject)
|
||||
v -> v
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_resource(uuid, subject) do
|
||||
case fetch_resource(uuid, subject) do
|
||||
{:ok, value} when value.deleted_at == nil ->
|
||||
Logger.info("Deleting removed resource #{value.name}")
|
||||
{:ok, _} = Resources.delete_resource(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
# Fetch policy by uuid, but follow the chain of replacements if any
|
||||
defp fetch_policy(uuid, subject) do
|
||||
case Policies.fetch_policy_by_id(uuid, subject) do
|
||||
{:ok, policy} when policy.replaced_by_policy_id != nil -> fetch_policy(policy.replaced_by_policy_id, subject)
|
||||
v -> v
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_policy(uuid, subject) do
|
||||
case fetch_policy(uuid, subject) do
|
||||
{:ok, value} when value.deleted_at == nil ->
|
||||
Logger.info("Deleting removed policy #{value.description}")
|
||||
{:ok, _} = Policies.delete_policy(value, subject)
|
||||
_ -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
defp cleanup_entity_type(account_slug, entity_type, cleanup_fn, temp_admin_subject) do
|
||||
# Get mapping for this entity type
|
||||
existing_entities = UuidMapping.get_entities(account_slug, entity_type)
|
||||
# Get current entities from account data
|
||||
current_entities = Process.get(:current_entities)
|
||||
# Determine which ones to remove
|
||||
removed_entity_ids = Map.keys(existing_entities) -- (current_entities[entity_type] || [])
|
||||
|
||||
# Process each entity to remove
|
||||
Enum.each(removed_entity_ids, fn entity_id ->
|
||||
case existing_entities[entity_id] do
|
||||
nil -> :ok
|
||||
uuid ->
|
||||
cleanup_fn.(uuid, temp_admin_subject)
|
||||
UuidMapping.remove_entity(account_slug, entity_type, entity_id)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp collect_current_entities(account_data) do
|
||||
%{
|
||||
"actors" => Map.keys(account_data["actors"] || %{}),
|
||||
"providers" => Map.keys(account_data["auth"] || %{}),
|
||||
"gateway_groups" => Map.keys(account_data["gatewayGroups"] || %{}),
|
||||
"relay_groups" => Map.keys(account_data["relayGroups"] || %{}),
|
||||
"actor_groups" => Map.keys(account_data["groups"] || %{}) ++ ["everyone"],
|
||||
"resources" => Map.keys(account_data["resources"] || %{}),
|
||||
"policies" => Map.keys(account_data["policies"] || %{})
|
||||
}
|
||||
end
|
||||
|
||||
defp nil_if_deleted_or_not_found(value) do
|
||||
case value do
|
||||
nil -> nil
|
||||
{:error, :not_found} -> nil
|
||||
{:ok, value} when value.deleted_at != nil -> nil
|
||||
v -> v
|
||||
end
|
||||
end
|
||||
|
||||
defp create_temp_admin(account, email_provider) do
|
||||
temp_admin_actor_email = "firezone-provision@localhost.local"
|
||||
temp_admin_actor_context = %Auth.Context{
|
||||
type: :browser,
|
||||
user_agent: "Unspecified/0.0",
|
||||
remote_ip: {127, 0, 0, 1},
|
||||
remote_ip_location_region: "N/A",
|
||||
remote_ip_location_city: "N/A",
|
||||
remote_ip_location_lat: 0.0,
|
||||
remote_ip_location_lon: 0.0
|
||||
}
|
||||
|
||||
{:ok, temp_admin_actor} =
|
||||
Actors.create_actor(account, %{
|
||||
type: :account_admin_user,
|
||||
name: "Provisioning"
|
||||
})
|
||||
|
||||
{:ok, temp_admin_actor_email_identity} =
|
||||
Auth.create_identity(temp_admin_actor, email_provider, %{
|
||||
provider_identifier: temp_admin_actor_email,
|
||||
provider_identifier_confirmation: temp_admin_actor_email
|
||||
})
|
||||
|
||||
{:ok, temp_admin_actor_token} =
|
||||
Auth.create_token(temp_admin_actor_email_identity, temp_admin_actor_context, "temporarynonce", DateTime.utc_now() |> DateTime.add(1, :hour))
|
||||
|
||||
{:ok, temp_admin_subject} =
|
||||
Auth.build_subject(temp_admin_actor_token, temp_admin_actor_context)
|
||||
|
||||
{temp_admin_subject, temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token}
|
||||
end
|
||||
|
||||
defp cleanup_temp_admin(temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token, subject) do
|
||||
Logger.info("Cleaning up temporary admin actor")
|
||||
{:ok, _} = Tokens.delete_token(temp_admin_actor_token, subject)
|
||||
{:ok, _} = Auth.delete_identity(temp_admin_actor_email_identity, subject)
|
||||
{:ok, _} = Actors.delete_actor(temp_admin_actor, subject)
|
||||
end
|
||||
|
||||
def provision() do
|
||||
Logger.info("Starting provisioning")
|
||||
|
||||
# Load desired state
|
||||
json_file = "provision-state.json"
|
||||
{:ok, raw_json} = File.read(json_file)
|
||||
{:ok, %{"accounts" => accounts}} = Jason.decode(raw_json)
|
||||
accounts = resolve_references(accounts)
|
||||
|
||||
# Load existing UUID mappings into the process dictionary.
|
||||
UuidMapping.load()
|
||||
|
||||
# Clean up removed accounts first
|
||||
current_account_slugs = Map.keys(accounts)
|
||||
existing_accounts = Map.keys(Process.get(:uuid_mappings)["accounts"])
|
||||
removed_accounts = existing_accounts -- current_account_slugs
|
||||
|
||||
Enum.each(removed_accounts, fn slug ->
|
||||
if uuid = get_in(Process.get(:uuid_mappings), ["accounts", slug, "id"]) do
|
||||
cleanup_account(uuid)
|
||||
# Remove the account from the UUID mapping.
|
||||
UuidMapping.remove_account(slug)
|
||||
end
|
||||
end)
|
||||
|
||||
multi = Enum.reduce(accounts, Ecto.Multi.new(), fn {slug, account_data}, multi ->
|
||||
account_attrs = atomize_keys(%{
|
||||
name: account_data["name"],
|
||||
slug: slug,
|
||||
features: Map.get(account_data, "features", %{}),
|
||||
metadata: Map.get(account_data, "metadata", %{}),
|
||||
limits: Map.get(account_data, "limits", %{})
|
||||
})
|
||||
|
||||
multi = multi
|
||||
|> Ecto.Multi.run({:account, slug}, fn repo, _changes ->
|
||||
case Accounts.fetch_account_by_id_or_slug(slug) do
|
||||
{:ok, acc} ->
|
||||
Logger.info("Updating existing account #{slug}")
|
||||
updated_acc = acc |> Ecto.Changeset.change(account_attrs) |> repo.update!()
|
||||
{:ok, {:existing, updated_acc}}
|
||||
_ ->
|
||||
Logger.info("Creating new account #{slug}")
|
||||
{:ok, account} = Accounts.create_account(account_attrs)
|
||||
|
||||
Logger.info("Creating internet gateway group")
|
||||
{:ok, internet_site} = Gateways.create_internet_group(account)
|
||||
|
||||
Logger.info("Creating internet resource")
|
||||
{:ok, _internet_resource} = Resources.create_internet_resource(account, internet_site)
|
||||
|
||||
# Store mapping of slug to UUID
|
||||
UuidMapping.update_account(slug, account.id)
|
||||
{:ok, {:new, account}}
|
||||
end
|
||||
end)
|
||||
|> Ecto.Multi.run({:everyone_group, slug}, fn _repo, changes ->
|
||||
case Map.get(changes, {:account, slug}) do
|
||||
{:new, account} ->
|
||||
Logger.info("Creating everyone group for new account")
|
||||
{:ok, actor_group} = Actors.create_managed_group(account, %{name: "Everyone"})
|
||||
UuidMapping.update_entities(slug, "actor_groups", %{"everyone" => actor_group.id})
|
||||
{:ok, actor_group}
|
||||
{:existing, _account} ->
|
||||
{:ok, :skipped}
|
||||
end
|
||||
end)
|
||||
|> Ecto.Multi.run({:email_provider, slug}, fn _repo, changes ->
|
||||
case Map.get(changes, {:account, slug}) do
|
||||
{:new, account} ->
|
||||
Logger.info("Creating default email provider for new account")
|
||||
Auth.create_provider(account, %{name: "Email", adapter: :email, adapter_config: %{}})
|
||||
{:existing, account} ->
|
||||
Auth.Provider.Query.not_disabled()
|
||||
|> Auth.Provider.Query.by_adapter(:email)
|
||||
|> Auth.Provider.Query.by_account_id(account.id)
|
||||
|> Repo.fetch(Auth.Provider.Query, [])
|
||||
end
|
||||
end)
|
||||
|> Ecto.Multi.run({:temp_admin, slug}, fn _repo, changes ->
|
||||
{_, account} = changes[{:account, slug}]
|
||||
email_provider = changes[{:email_provider, slug}]
|
||||
{:ok, create_temp_admin(account, email_provider)}
|
||||
end)
|
||||
|
||||
# Clean up removed entities for this account after we have an admin subject
|
||||
multi = multi
|
||||
|> Ecto.Multi.run({:cleanup_entities, slug}, fn _repo, changes ->
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
|
||||
# Store current entities in process dictionary for our helper function
|
||||
current_entities = collect_current_entities(account_data)
|
||||
Process.put(:current_entities, current_entities)
|
||||
|
||||
# Define entity types and their cleanup functions
|
||||
entity_types = [
|
||||
{"actors", &cleanup_actor/2},
|
||||
{"providers", &cleanup_provider/2},
|
||||
{"gateway_groups", &cleanup_gateway_group/2},
|
||||
{"relay_groups", &cleanup_relay_group/2},
|
||||
{"actor_groups", &cleanup_actor_group/2},
|
||||
{"resources", &cleanup_resource/2},
|
||||
{"policies", &cleanup_policy/2}
|
||||
]
|
||||
|
||||
# Clean up each entity type
|
||||
Enum.each(entity_types, fn {entity_type, cleanup_fn} ->
|
||||
cleanup_entity_type(slug, entity_type, cleanup_fn, temp_admin_subject)
|
||||
end)
|
||||
|
||||
{:ok, :cleaned}
|
||||
end)
|
||||
|
||||
# Create or update actors
|
||||
multi = Enum.reduce(account_data["actors"] || %{}, multi, fn {external_id, actor_data}, multi ->
|
||||
actor_attrs = atomize_keys(%{
|
||||
name: actor_data["name"],
|
||||
type: String.to_atom(actor_data["type"])
|
||||
})
|
||||
|
||||
Ecto.Multi.run(multi, {:actor, slug, external_id}, fn _repo, changes ->
|
||||
{_, account} = changes[{:account, slug}]
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "actors", external_id)
|
||||
case uuid && Actors.fetch_actor_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
|
||||
nil ->
|
||||
Logger.info("Creating new actor #{actor_data["name"]}")
|
||||
{:ok, actor} = Actors.create_actor(account, actor_attrs)
|
||||
# Update the mapping without manually handling Process.get/put.
|
||||
UuidMapping.update_entities(slug, "actors", %{external_id => actor.id})
|
||||
{:ok, {:new, actor}}
|
||||
{:ok, existing_actor} ->
|
||||
Logger.info("Updating existing actor #{actor_data["name"]}")
|
||||
{:ok, updated_act} = Actors.update_actor(existing_actor, actor_attrs, temp_admin_subject)
|
||||
{:ok, {:existing, updated_act}}
|
||||
end
|
||||
end)
|
||||
|> Ecto.Multi.run({:actor_identity, slug, external_id}, fn repo, changes ->
|
||||
email_provider = changes[{:email_provider, slug}]
|
||||
case Map.get(changes, {:actor, slug, external_id}) do
|
||||
{:new, actor} ->
|
||||
Logger.info("Creating actor email identity")
|
||||
Auth.create_identity(actor, email_provider, %{
|
||||
provider_identifier: actor_data["email"],
|
||||
provider_identifier_confirmation: actor_data["email"]
|
||||
})
|
||||
{:existing, actor} ->
|
||||
Logger.info("Updating actor email identity")
|
||||
{:ok, identity} = Auth.Identity.Query.not_deleted()
|
||||
|> Auth.Identity.Query.by_actor_id(actor.id)
|
||||
|> Auth.Identity.Query.by_provider_id(email_provider.id)
|
||||
|> Repo.fetch(Auth.Identity.Query, [])
|
||||
|
||||
{:ok, identity |> Ecto.Changeset.change(%{
|
||||
provider_identifier: actor_data["email"]
|
||||
}) |> repo.update!()}
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
# Create or update providers
|
||||
multi = Enum.reduce(account_data["auth"] || %{}, multi, fn {external_id, provider_data}, multi ->
|
||||
Ecto.Multi.run(multi, {:provider, slug, external_id}, fn repo, changes ->
|
||||
provider_attrs = %{
|
||||
name: provider_data["name"],
|
||||
adapter: String.to_atom(provider_data["adapter"]),
|
||||
adapter_config: provider_data["adapter_config"]
|
||||
}
|
||||
|
||||
{_, account} = changes[{:account, slug}]
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "providers", external_id)
|
||||
case uuid && Auth.fetch_provider_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
|
||||
nil ->
|
||||
Logger.info("Creating new provider #{provider_data["name"]}")
|
||||
{:ok, provider} = Auth.create_provider(account, provider_attrs)
|
||||
UuidMapping.update_entities(slug, "providers", %{external_id => provider.id})
|
||||
{:ok, provider}
|
||||
{:ok, existing} ->
|
||||
Logger.info("Updating existing provider #{provider_data["name"]}")
|
||||
{:ok, existing |> Ecto.Changeset.change(provider_attrs) |> repo.update!()}
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
# Create or update gateway_groups
|
||||
multi = Enum.reduce(account_data["gatewayGroups"] || %{}, multi, fn {external_id, gateway_group_data}, multi ->
|
||||
Ecto.Multi.run(multi, {:gateway_group, slug, external_id}, fn _repo, changes ->
|
||||
gateway_group_attrs = %{
|
||||
name: gateway_group_data["name"],
|
||||
tokens: [%{}]
|
||||
}
|
||||
|
||||
{_, account} = changes[{:account, slug}]
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "gateway_groups", external_id)
|
||||
case uuid && Gateways.fetch_group_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
|
||||
nil ->
|
||||
Logger.info("Creating new gateway group #{gateway_group_data["name"]}")
|
||||
gateway_group = account
|
||||
|> Gateways.Group.Changeset.create(gateway_group_attrs, temp_admin_subject)
|
||||
|> Repo.insert!()
|
||||
UuidMapping.update_entities(slug, "gateway_groups", %{external_id => gateway_group.id})
|
||||
{:ok, gateway_group}
|
||||
{:ok, existing} ->
|
||||
# Nothing to update
|
||||
{:ok, existing}
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
# Create or update relay_groups
|
||||
multi = Enum.reduce(account_data["relayGroups"] || %{}, multi, fn {external_id, relay_group_data}, multi ->
|
||||
Ecto.Multi.run(multi, {:relay_group, slug, external_id}, fn _repo, changes ->
|
||||
relay_group_attrs = %{
|
||||
name: relay_group_data["name"]
|
||||
}
|
||||
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "relay_groups", external_id)
|
||||
existing_relay_group = uuid && Relays.fetch_group_by_id(uuid, temp_admin_subject)
|
||||
case existing_relay_group do
|
||||
v when v in [nil, {:error, :not_found}] ->
|
||||
Logger.info("Creating new relay group #{relay_group_data["name"]}")
|
||||
{:ok, relay_group} = Relays.create_group(relay_group_attrs, temp_admin_subject)
|
||||
UuidMapping.update_entities(slug, "relay_groups", %{external_id => relay_group.id})
|
||||
{:ok, relay_group}
|
||||
{:ok, existing} ->
|
||||
# Nothing to update
|
||||
{:ok, existing}
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
# Create or update actor_groups
|
||||
multi = Enum.reduce(account_data["groups"] || %{}, multi, fn {external_id, actor_group_data}, multi ->
|
||||
Ecto.Multi.run(multi, {:actor_group, slug, external_id}, fn _repo, changes ->
|
||||
actor_group_attrs = %{
|
||||
name: actor_group_data["name"],
|
||||
type: :static
|
||||
}
|
||||
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "actor_groups", external_id)
|
||||
case uuid && Actors.fetch_group_by_id(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
|
||||
nil ->
|
||||
Logger.info("Creating new actor group #{actor_group_data["name"]}")
|
||||
{:ok, actor_group} = Actors.create_group(actor_group_attrs, temp_admin_subject)
|
||||
UuidMapping.update_entities(slug, "actor_groups", %{external_id => actor_group.id})
|
||||
{:ok, actor_group}
|
||||
{:ok, existing} ->
|
||||
# Nothing to update
|
||||
{:ok, existing}
|
||||
end
|
||||
end)
|
||||
|> Ecto.Multi.run({:actor_group_members, slug, external_id}, fn repo, changes ->
|
||||
{_, account} = changes[{:account, slug}]
|
||||
group_uuid = UuidMapping.get_entity(slug, "actor_groups", external_id)
|
||||
|
||||
memberships =
|
||||
Actors.Membership.Query.all()
|
||||
|> Actors.Membership.Query.by_group_id(group_uuid)
|
||||
|> Actors.Membership.Query.returning_all()
|
||||
|> Repo.all()
|
||||
|
||||
existing_members = Enum.map(memberships, fn membership -> membership.actor_id end)
|
||||
desired_members = Enum.map(actor_group_data["members"] || [], fn member ->
|
||||
uuid = UuidMapping.get_entity(slug, "actors", member)
|
||||
if uuid == nil do
|
||||
raise "Cannot find provisioned actor #{member} to add to group"
|
||||
end
|
||||
uuid
|
||||
end)
|
||||
|
||||
missing_members = desired_members -- existing_members
|
||||
untracked_members = existing_members -- desired_members
|
||||
|
||||
Logger.info("Updating members for actor group #{external_id}")
|
||||
Enum.each(missing_members || [], fn actor_uuid ->
|
||||
Logger.info("Adding member #{external_id}")
|
||||
Actors.Membership.Changeset.upsert(account.id, %Actors.Membership{}, %{
|
||||
group_id: group_uuid,
|
||||
actor_id: actor_uuid
|
||||
})
|
||||
|> repo.insert!()
|
||||
end)
|
||||
|
||||
if actor_group_data["forceMembers"] == true do
|
||||
# Remove untracked members
|
||||
to_delete = Enum.map(untracked_members, fn actor_uuid -> {group_uuid, actor_uuid} end)
|
||||
if to_delete != [] do
|
||||
Actors.Membership.Query.by_group_id_and_actor_id({:in, to_delete})
|
||||
|> repo.delete_all()
|
||||
end
|
||||
end
|
||||
|
||||
{:ok, nil}
|
||||
end)
|
||||
end)
|
||||
|
||||
# Create or update resources
|
||||
multi = Enum.reduce(account_data["resources"] || %{}, multi, fn {external_id, resource_data}, multi ->
|
||||
Ecto.Multi.run(multi, {:resource, slug, external_id}, fn _repo, changes ->
|
||||
resource_attrs = %{
|
||||
type: String.to_atom(resource_data["type"]),
|
||||
name: resource_data["name"],
|
||||
address: resource_data["address"],
|
||||
address_description: resource_data["address_description"],
|
||||
connections: Enum.map(resource_data["gatewayGroups"] || [], fn group ->
|
||||
%{gateway_group_id: UuidMapping.get_entity(slug, "gateway_groups", group)}
|
||||
end),
|
||||
filters: Enum.map(resource_data["filters"] || [], fn filter ->
|
||||
%{
|
||||
ports: filter["ports"] || [],
|
||||
protocol: String.to_atom(filter["protocol"])
|
||||
}
|
||||
end)
|
||||
}
|
||||
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "resources", external_id)
|
||||
case uuid && fetch_resource(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
|
||||
nil ->
|
||||
Logger.info("Creating new resource #{resource_data["name"]}")
|
||||
{:ok, resource} = Resources.create_resource(resource_attrs, temp_admin_subject)
|
||||
UuidMapping.update_entities(slug, "resources", %{external_id => resource.id})
|
||||
{:ok, resource}
|
||||
{:ok, existing} ->
|
||||
existing = Repo.preload(existing, :connections)
|
||||
Logger.info("Updating existing resource #{resource_data["name"]}")
|
||||
only_updated_attrs = resource_attrs
|
||||
|> Enum.reject(fn {key, value} ->
|
||||
case key do
|
||||
# Compare connections by gateway_group_id only
|
||||
:connections -> value == Enum.map(existing.connections || [], fn conn -> Map.take(conn, [:gateway_group_id]) end)
|
||||
# Compare filters by ports and protocol only
|
||||
:filters -> value == Enum.map(existing.filters || [], fn filter -> Map.take(filter, [:ports, :protocol]) end)
|
||||
_ -> Map.get(existing, key) == value
|
||||
end
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
if only_updated_attrs == %{} do
|
||||
{:ok, existing}
|
||||
else
|
||||
resource = case existing |> Resources.update_resource(resource_attrs, temp_admin_subject) do
|
||||
{:replaced, _old, new} ->
|
||||
UuidMapping.update_entities(slug, "resources", %{external_id => new.id})
|
||||
new
|
||||
{:updated, value} -> value
|
||||
x -> x
|
||||
end
|
||||
|
||||
{:ok, resource}
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
# Create or update policies
|
||||
multi = Enum.reduce(account_data["policies"] || %{}, multi, fn {external_id, policy_data}, multi ->
|
||||
Ecto.Multi.run(multi, {:policy, slug, external_id}, fn _repo, changes ->
|
||||
policy_attrs = %{
|
||||
description: policy_data["description"],
|
||||
actor_group_id: UuidMapping.get_entity(slug, "actor_groups", policy_data["group"]),
|
||||
resource_id: UuidMapping.get_entity(slug, "resources", policy_data["resource"])
|
||||
}
|
||||
|
||||
{temp_admin_subject, _, _, _} = changes[{:temp_admin, slug}]
|
||||
uuid = UuidMapping.get_entity(slug, "policies", external_id)
|
||||
case uuid && fetch_policy(uuid, temp_admin_subject) |> nil_if_deleted_or_not_found() do
|
||||
nil ->
|
||||
Logger.info("Creating new policy #{policy_data["name"]}")
|
||||
{:ok, policy} = Policies.create_policy(policy_attrs, temp_admin_subject)
|
||||
UuidMapping.update_entities(slug, "policies", %{external_id => policy.id})
|
||||
{:ok, policy}
|
||||
{:ok, existing} ->
|
||||
Logger.info("Updating existing policy #{policy_data["name"]}")
|
||||
only_updated_attrs = policy_attrs
|
||||
|> Enum.reject(fn {key, value} -> Map.get(existing, key) == value end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
if only_updated_attrs == %{} do
|
||||
{:ok, existing}
|
||||
else
|
||||
policy = case existing |> Policies.update_policy(policy_attrs, temp_admin_subject) do
|
||||
{:replaced, _old, new} ->
|
||||
UuidMapping.update_entities(slug, "policies", %{external_id => new.id})
|
||||
new
|
||||
{:updated, value} -> value
|
||||
x -> x
|
||||
end
|
||||
|
||||
{:ok, policy}
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
# Clean up temporary admin after all operations
|
||||
multi |> Ecto.Multi.run({:cleanup_temp_admin, slug}, fn _repo, changes ->
|
||||
{temp_admin_subject, temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token} =
|
||||
changes[{:temp_admin, slug}]
|
||||
|
||||
cleanup_temp_admin(temp_admin_actor, temp_admin_actor_email_identity, temp_admin_actor_token, temp_admin_subject)
|
||||
{:ok, :cleaned}
|
||||
end)
|
||||
end)
|
||||
|> Ecto.Multi.run({:save_state}, fn _repo, _changes ->
|
||||
# Save all UUID mappings to disk.
|
||||
UuidMapping.save()
|
||||
{:ok, :saved}
|
||||
end)
|
||||
|
||||
case Repo.transaction(multi) do
|
||||
{:ok, _result} ->
|
||||
Logger.info("Provisioning completed successfully")
|
||||
{:error, step, reason, _changes} ->
|
||||
Logger.error("Provisioning failed at step #{inspect(step)}, no changes were applied: #{inspect(reason)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Provision.provision()
|
||||
|
|
@ -9,12 +9,8 @@ let
|
|||
attrNames
|
||||
boolToString
|
||||
concatLines
|
||||
concatLists
|
||||
concatMapAttrs
|
||||
concatStringsSep
|
||||
filterAttrs
|
||||
filterAttrsRecursive
|
||||
flip
|
||||
forEach
|
||||
getExe
|
||||
isBool
|
||||
|
|
@ -26,16 +22,11 @@ let
|
|||
mkMerge
|
||||
mkOption
|
||||
mkPackageOption
|
||||
optionalAttrs
|
||||
optionalString
|
||||
recursiveUpdate
|
||||
subtractLists
|
||||
toUpper
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.services.firezone.server;
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
availableAuthAdapters = [
|
||||
"email"
|
||||
"openid_connect"
|
||||
|
|
@ -47,28 +38,6 @@ let
|
|||
"jumpcloud"
|
||||
];
|
||||
|
||||
typePortRange =
|
||||
types.coercedTo types.port
|
||||
(x: {
|
||||
from = x;
|
||||
to = x;
|
||||
})
|
||||
(
|
||||
types.submodule {
|
||||
options = {
|
||||
from = mkOption {
|
||||
type = types.port;
|
||||
description = "The start of the port range, inclusive.";
|
||||
};
|
||||
|
||||
to = mkOption {
|
||||
type = types.port;
|
||||
description = "The end of the port range, inclusive.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
# All non-secret environment variables or the given component
|
||||
collectEnvironment =
|
||||
component:
|
||||
|
|
@ -119,29 +88,6 @@ let
|
|||
)
|
||||
);
|
||||
|
||||
provisionStateJson =
|
||||
let
|
||||
# Convert clientSecretFile options into the real counterpart
|
||||
augmentedAccounts = flip mapAttrs cfg.provision.accounts (
|
||||
accountName: account:
|
||||
account
|
||||
// {
|
||||
auth = flip mapAttrs account.auth (
|
||||
authName: auth:
|
||||
recursiveUpdate auth (
|
||||
optionalAttrs (auth.adapter_config.clientSecretFile != null) {
|
||||
adapter_config.client_secret = "{env:AUTH_CLIENT_SECRET_${toUpper accountName}_${toUpper authName}}";
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
in
|
||||
jsonFormat.generate "provision-state.json" {
|
||||
# Do not include any clientSecretFile attributes in the resulting json
|
||||
accounts = filterAttrsRecursive (k: _: k != "clientSecretFile") augmentedAccounts;
|
||||
};
|
||||
|
||||
commonServiceConfig = {
|
||||
AmbientCapabilities = [ ];
|
||||
CapabilityBoundingSet = [ ];
|
||||
|
|
@ -222,6 +168,12 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [ "services" "firezone" "server" "provision" ] ''
|
||||
Firezone provisioning support has been removed due to outsized maintenance efforts. See https://github.com/NixOS/nixpkgs/pull/529428.
|
||||
'')
|
||||
];
|
||||
|
||||
options.services.firezone.server = {
|
||||
enable = mkEnableOption "all Firezone components";
|
||||
enableLocalDB = mkEnableOption "a local postgresql database for Firezone";
|
||||
|
|
@ -521,393 +473,9 @@ in
|
|||
description = "A list of trusted proxies";
|
||||
};
|
||||
};
|
||||
|
||||
provision = {
|
||||
enable = mkEnableOption "provisioning of the Firezone domain server";
|
||||
accounts = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
freeformType = jsonFormat.type;
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The account name";
|
||||
example = "My Organization";
|
||||
};
|
||||
|
||||
features =
|
||||
let
|
||||
mkFeatureOption =
|
||||
name: default:
|
||||
mkOption {
|
||||
type = types.bool;
|
||||
inherit default;
|
||||
description = "Whether to enable the `${name}` feature for this account.";
|
||||
};
|
||||
in
|
||||
{
|
||||
policy_conditions = mkFeatureOption "policy_conditions" true;
|
||||
multi_site_resources = mkFeatureOption "multi_site_resources" true;
|
||||
traffic_filters = mkFeatureOption "traffic_filters" true;
|
||||
self_hosted_relays = mkFeatureOption "self_hosted_relays" true;
|
||||
idp_sync = mkFeatureOption "idp_sync" true;
|
||||
rest_api = mkFeatureOption "rest_api" true;
|
||||
internet_resource = mkFeatureOption "internet_resource" true;
|
||||
};
|
||||
|
||||
actors = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
type = mkOption {
|
||||
type = types.enum [
|
||||
"account_admin_user"
|
||||
"account_user"
|
||||
"service_account"
|
||||
"api_client"
|
||||
];
|
||||
description = "The account type";
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The name of this actor";
|
||||
};
|
||||
|
||||
email = mkOption {
|
||||
type = types.str;
|
||||
description = "The email address used to authenticate as this account";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
admin = {
|
||||
type = "account_admin_user";
|
||||
name = "Admin";
|
||||
email = "admin@myorg.example.com";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All actors (users) to provision. The attribute name will only
|
||||
be used to track the actor and does not have any significance
|
||||
for Firezone.
|
||||
'';
|
||||
};
|
||||
|
||||
auth = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
freeformType = jsonFormat.type;
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The name of this authentication provider";
|
||||
};
|
||||
|
||||
adapter = mkOption {
|
||||
type = types.enum availableAuthAdapters;
|
||||
description = "The auth adapter type";
|
||||
};
|
||||
|
||||
adapter_config.clientSecretFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
A file containing a the client secret for an openid_connect adapter.
|
||||
You only need to set this if this is an openid_connect provider.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
myoidcprovider = {
|
||||
adapter = "openid_connect";
|
||||
adapter_config = {
|
||||
client_id = "clientid";
|
||||
clientSecretFile = "/run/secrets/oidc-client-secret";
|
||||
response_type = "code";
|
||||
scope = "openid email name";
|
||||
discovery_document_uri = "https://auth.example.com/.well-known/openid-configuration";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All authentication providers to provision. The attribute name
|
||||
will only be used to track the provider and does not have any
|
||||
significance for Firezone.
|
||||
'';
|
||||
};
|
||||
|
||||
resources = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
type = mkOption {
|
||||
type = types.enum [
|
||||
"dns"
|
||||
"cidr"
|
||||
"ip"
|
||||
];
|
||||
description = "The resource type";
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The name of this resource";
|
||||
};
|
||||
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = "The address of this resource. Depending on the resource type, this should be an ip, ip with cidr mask or a domain.";
|
||||
};
|
||||
|
||||
addressDescription = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "An optional description for resource address, usually a full link to the resource including a schema.";
|
||||
};
|
||||
|
||||
gatewayGroups = mkOption {
|
||||
type = types.nonEmptyListOf types.str;
|
||||
description = "A list of gateway groups (sites) which can reach the resource and may be used to connect to it.";
|
||||
};
|
||||
|
||||
filters = mkOption {
|
||||
type = types.listOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
protocol = mkOption {
|
||||
type = types.enum [
|
||||
"icmp"
|
||||
"tcp"
|
||||
"udp"
|
||||
];
|
||||
description = "The protocol to allow";
|
||||
};
|
||||
|
||||
ports = mkOption {
|
||||
type = types.listOf typePortRange;
|
||||
example = [
|
||||
443
|
||||
{
|
||||
from = 8080;
|
||||
to = 8100;
|
||||
}
|
||||
];
|
||||
default = [ ];
|
||||
apply =
|
||||
xs: map (x: if x.from == x.to then toString x.from else "${toString x.from} - ${toString x.to}") xs;
|
||||
description = "Either a single port or port range to allow. Both bounds are inclusive.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = [ ];
|
||||
description = "A list of filter to restrict traffic. If no filters are given, all traffic is allowed.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
vaultwarden = {
|
||||
type = "dns";
|
||||
name = "Vaultwarden";
|
||||
address = "vault.example.com";
|
||||
address_description = "https://vault.example.com";
|
||||
gatewayGroups = [ "my-site" ];
|
||||
filters = [
|
||||
{ protocol = "icmp"; }
|
||||
{
|
||||
protocol = "tcp";
|
||||
ports = [
|
||||
80
|
||||
443
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All resources to provision. The attribute name will only be used to
|
||||
track the resource and does not have any significance for Firezone.
|
||||
'';
|
||||
};
|
||||
|
||||
policies = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
description = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The description of this policy";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
description = "The group which should be allowed access to the given resource.";
|
||||
};
|
||||
|
||||
resource = mkOption {
|
||||
type = types.str;
|
||||
description = "The resource to which access should be allowed.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
access_vaultwarden = {
|
||||
name = "Allow anyone to access vaultwarden";
|
||||
group = "everyone";
|
||||
resource = "vaultwarden";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All policies to provision. The attribute name will only be used to
|
||||
track the policy and does not have any significance for Firezone.
|
||||
'';
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The name of this group";
|
||||
};
|
||||
|
||||
members = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
description = "The members of this group";
|
||||
};
|
||||
|
||||
forceMembers = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Ensure that only the given members are part of this group at every server start.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
users = {
|
||||
name = "Users";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All groups to provision. The attribute name will only be used
|
||||
to track the group and does not have any significance for
|
||||
Firezone.
|
||||
|
||||
A group named `everyone` will automatically be managed by Firezone.
|
||||
'';
|
||||
};
|
||||
|
||||
relayGroups = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The name of this relay group";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
my-relays = {
|
||||
name = "My Relays";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All relay groups to provision. The attribute name
|
||||
will only be used to track the relay group and does not have any
|
||||
significance for Firezone.
|
||||
'';
|
||||
};
|
||||
|
||||
gatewayGroups = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "The name of this gateway group";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
my-gateways = {
|
||||
name = "My Gateways";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All gateway groups (sites) to provision. The attribute name
|
||||
will only be used to track the gateway group and does not have any
|
||||
significance for Firezone.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
example = {
|
||||
main = {
|
||||
name = "My Account / Organization";
|
||||
metadata.stripe.billing_email = "org@myorg.example.com";
|
||||
features.rest_api = false;
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
All accounts to provision. The attribute name specified here will
|
||||
become the account slug. By using `"{file:/path/to/file}"` as a
|
||||
string value anywhere in these settings, the provisioning script will
|
||||
replace that value with the content of the given file at runtime.
|
||||
|
||||
Please refer to the [Firezone source code](https://github.com/firezone/firezone/blob/main/elixir/apps/domain/lib/domain/accounts/account.ex)
|
||||
for all available properties.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.provision.enable -> cfg.domain.enable;
|
||||
message = "Provisioning must be done on a machine running the firezone domain server";
|
||||
}
|
||||
]
|
||||
++ concatLists (
|
||||
flip mapAttrsToList cfg.provision.accounts (
|
||||
accountName: accountCfg:
|
||||
[
|
||||
{
|
||||
assertion = (builtins.match "^[[:lower:]_-]+$" accountName) != null;
|
||||
message = "An account name must contain only lowercase characters and underscores, as it will be used as the URL slug for this account.";
|
||||
}
|
||||
]
|
||||
++ flip mapAttrsToList accountCfg.auth (
|
||||
authName: _: {
|
||||
assertion = (builtins.match "^[[:alnum:]_-]+$" authName) != null;
|
||||
message = "The authentication provider attribute key must contain only letters, numbers, underscores or dashes.";
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
# Enable all components if the main server is enabled
|
||||
(mkIf cfg.enable {
|
||||
services.firezone.server.domain.enable = true;
|
||||
|
|
@ -1015,7 +583,7 @@ in
|
|||
FEATURE_INTERNET_RESOURCE_ENABLED = mkDefault true;
|
||||
FEATURE_TRAFFIC_FILTERS_ENABLED = mkDefault true;
|
||||
|
||||
FEATURE_SIGN_UP_ENABLED = mkDefault (!cfg.provision.enable);
|
||||
FEATURE_SIGN_UP_ENABLED = mkDefault true;
|
||||
|
||||
WEB_EXTERNAL_URL = mkDefault cfg.web.externalUrl;
|
||||
API_EXTERNAL_URL = mkDefault cfg.api.externalUrl;
|
||||
|
|
@ -1066,19 +634,6 @@ in
|
|||
OUTBOUND_EMAIL_SMTP_PASSWORD = cfg.smtp.passwordFile;
|
||||
};
|
||||
})
|
||||
(mkIf cfg.provision.enable {
|
||||
# Load client secrets from authentication providers
|
||||
services.firezone.server.settingsSecret = flip concatMapAttrs cfg.provision.accounts (
|
||||
accountName: accountCfg:
|
||||
flip concatMapAttrs accountCfg.auth (
|
||||
authName: authCfg:
|
||||
optionalAttrs (authCfg.adapter_config.clientSecretFile != null) {
|
||||
"AUTH_CLIENT_SECRET_${toUpper accountName}_${toUpper authName}" =
|
||||
authCfg.adapter_config.clientSecretFile;
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
(mkIf (cfg.openClusterFirewall && cfg.domain.enable) {
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
cfg.domain.settings.ERLANG_DISTRIBUTION_PORT
|
||||
|
|
@ -1156,14 +711,6 @@ in
|
|||
fi
|
||||
count=$((count++))
|
||||
done
|
||||
''
|
||||
+ optionalString cfg.provision.enable ''
|
||||
# Wait for server to fully come up. Not ideal to use sleep, but at least it works.
|
||||
sleep 1
|
||||
|
||||
${loadSecretEnvironment "domain"}
|
||||
ln -sTf ${provisionStateJson} provision-state.json
|
||||
${getExe cfg.domain.package} rpc 'Code.eval_file("${./provision.exs}")'
|
||||
'';
|
||||
|
||||
environment = collectEnvironment "domain";
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ let
|
|||
toString v
|
||||
else if lib.isString v then
|
||||
v
|
||||
else if lib.isPath v then
|
||||
v
|
||||
else if true == v then
|
||||
"yes"
|
||||
else if false == v then
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ let
|
|||
]
|
||||
++ lib.optionals cfg.userControlled [
|
||||
# set up client sockets directory
|
||||
"+${pkgs.coreutils}/bin/mkdir /run/wpa_supplicant/client"
|
||||
"+${pkgs.coreutils}/bin/mkdir -p /run/wpa_supplicant/client"
|
||||
"+${pkgs.coreutils}/bin/chown wpa_supplicant:wpa_supplicant /run/wpa_supplicant/client"
|
||||
"+${pkgs.coreutils}/bin/chmod g=u /run/wpa_supplicant/client"
|
||||
];
|
||||
|
|
|
|||
95
nixos/modules/services/scheduling/scx-loader.nix
Normal file
95
nixos/modules/services/scheduling/scx-loader.nix
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.scx-loader;
|
||||
settingsFormat = pkgs.formats.toml { };
|
||||
configFile = settingsFormat.generate "scx_loader.toml" (
|
||||
lib.filterAttrsRecursive (_: v: v != null) cfg.config
|
||||
);
|
||||
|
||||
schedulers = builtins.concatMap (
|
||||
x: x.passthru.schedulers or (throw "Scheduler not found in package ${x.name}")
|
||||
) cfg.schedsPackages;
|
||||
in
|
||||
{
|
||||
options.services.scx-loader = {
|
||||
enable = lib.mkEnableOption "SCX Loader service, a daemon to run schedulers from userspace using dbus. This requires kernel version 6.12 and later.";
|
||||
|
||||
package = lib.mkPackageOption pkgs "scx-loader" { };
|
||||
|
||||
schedsPackages = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
default = [ pkgs.scx.rustscheds ];
|
||||
defaultText = lib.literalExpression "[ pkgs.scx.rustscheds ]";
|
||||
example = lib.literalExpression "[ pkgs.scx.full ]";
|
||||
description = ''
|
||||
`scx` package to use. Defaults to `scx.rustscheds`, which includes all currently by `scx_loader` supported schedulers.
|
||||
'';
|
||||
};
|
||||
|
||||
config = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
|
||||
options = {
|
||||
default_sched = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "scx_bpfland";
|
||||
description = ''
|
||||
Default scheduler that will be started automatically when `scx_loader` starts.
|
||||
If not set or set to an empty string, `scx_loader` will not start any scheduler by default.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
Configuration for `scx_loader`.
|
||||
|
||||
See <https://github.com/sched-ext/scx-loader/blob/main/crates/scx_loader/configuration.md> for the full list of options.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.12";
|
||||
message = "SCX is only supported on kernel version 6.12 and above.";
|
||||
}
|
||||
{
|
||||
assertion = !config.services.scx.enable;
|
||||
message = "services.scx and services.scx_loader cannot be enabled simultaneously. Please enable only one of them.";
|
||||
}
|
||||
{
|
||||
assertion =
|
||||
cfg.config.default_sched == null || lib.elem cfg.config.default_sched ([ "" ] ++ schedulers);
|
||||
message = ''
|
||||
Invalid default scheduler: ${cfg.config.default_sched}. It must be one of: ${lib.concatStringsSep ", " schedulers}.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = [ cfg.package ] ++ cfg.schedsPackages;
|
||||
systemd.packages = [ cfg.package ];
|
||||
services.dbus.packages = [ cfg.package ];
|
||||
|
||||
security.polkit.enable = true;
|
||||
|
||||
systemd.services.scx_loader = {
|
||||
path = cfg.schedsPackages;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
TemporaryFileSystem = [ "/etc" ];
|
||||
BindReadOnlyPaths = [ "${configFile.outPath}:/etc/scx_loader.toml" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ ccicnce113424 ];
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ let
|
|||
file = pkgs.writeText "rule" (builtins.toJSON cfg);
|
||||
}
|
||||
);
|
||||
stateDir = lib.strings.match "/var/lib/([^/]+)/.+" cfg.settings.Rules.Path;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
|
@ -105,10 +106,9 @@ in
|
|||
"iptables"
|
||||
"nftables"
|
||||
];
|
||||
default = if config.networking.nftables.enable then "nftables" else "iptables";
|
||||
defaultText = lib.literalExpression ''if config.networking.nftables.enable then "nftables" else "iptables"'';
|
||||
default = "nftables";
|
||||
description = ''
|
||||
Which firewall backend to use.
|
||||
Which firewall backend to use. `nftables` ruleset can be used for `iptables` firewall too, if `iptables` is built with nftables compatibility.
|
||||
'';
|
||||
};
|
||||
Ebpf.ModulesPath = lib.mkOption {
|
||||
|
|
@ -139,7 +139,10 @@ in
|
|||
};
|
||||
|
||||
Rules.Path = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
type = lib.types.pathWith {
|
||||
inStore = false;
|
||||
absolute = true;
|
||||
};
|
||||
default = "/var/lib/opensnitch/rules";
|
||||
description = ''
|
||||
Path to the directory where firewall rules can be found and will
|
||||
|
|
@ -158,6 +161,12 @@ in
|
|||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = stateDir != null;
|
||||
message = "`config.services.opensnitch.settings.Rules.Path` must be a sub-directory of /var/lib/, currently is ${cfg.settings.Rules.Path}";
|
||||
}
|
||||
];
|
||||
|
||||
security.auditd = lib.mkIf (cfg.settings.ProcMonitorMethod == "audit") {
|
||||
enable = true;
|
||||
|
|
@ -174,8 +183,14 @@ in
|
|||
""
|
||||
"${lib.getExe' cfg.package "opensnitchd"} --config-file ${cfg.configFile}"
|
||||
];
|
||||
StateDirectory = builtins.head stateDir; # match produces a list. Null case covered by assertion.
|
||||
};
|
||||
preStart = lib.mkIf (cfg.rules != { }) (
|
||||
preStart = ''
|
||||
# assert rules directory exists before service starts
|
||||
# will be in StateDirectory due to assertion
|
||||
mkdir -p ${cfg.settings.Rules.Path}
|
||||
''
|
||||
+ lib.optionalString (cfg.rules != { }) (
|
||||
let
|
||||
rules = lib.flip lib.mapAttrsToList predefinedRules (
|
||||
file: content: {
|
||||
|
|
@ -205,13 +220,12 @@ in
|
|||
''
|
||||
);
|
||||
};
|
||||
tmpfiles.rules = [
|
||||
"d ${cfg.settings.Rules.Path} 0750 root root - -"
|
||||
"L+ /etc/opensnitchd/network_aliases.json - - - - ${cfg.package}/etc/opensnitchd/network_aliases.json"
|
||||
"L+ /etc/opensnitchd/system-fw.json - - - - ${cfg.package}/etc/opensnitchd/system-fw.json"
|
||||
];
|
||||
};
|
||||
|
||||
environment.etc."opensnitchd/network_aliases.json".source =
|
||||
"${cfg.package}/etc/opensnitchd/network_aliases.json";
|
||||
environment.etc."opensnitchd/system-fw.json".source =
|
||||
"${cfg.package}/etc/opensnitchd/system-fw.json";
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ in
|
|||
ExecStart = lib.getExe pkgs.lauti;
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
StateDirectory = default;
|
||||
EnvironmentFile = [ cfg.secrets ];
|
||||
EnvironmentFile = cfg.secrets;
|
||||
|
||||
# hardening
|
||||
AmbientCapabilities = "";
|
||||
|
|
|
|||
|
|
@ -71,10 +71,12 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
system.activationScripts.setup-cde = ''
|
||||
mkdir -p /var/dt/{tmp,appconfig/appmanager}
|
||||
chmod a+w+t /var/dt/{tmp,appconfig/appmanager}
|
||||
'';
|
||||
systemd.tmpfiles.settings."10-cde" = {
|
||||
"/var/dt".d.mode = "0755";
|
||||
"/var/dt/tmp".d.mode = "1777";
|
||||
"/var/dt/appconfig".d.mode = "0755";
|
||||
"/var/dt/appconfig/appmanager".d.mode = "1777";
|
||||
};
|
||||
|
||||
services.xserver.desktopManager.session = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,13 +97,13 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [ "boot" "bootspec" "enable" ] ''
|
||||
Bootspec is now always generated and can no longer be disabled.
|
||||
'')
|
||||
];
|
||||
|
||||
options.boot.bootspec = {
|
||||
enable =
|
||||
lib.mkEnableOption "the generation of RFC-0125 bootspec in $system/boot.json, e.g. /run/current-system/boot.json"
|
||||
// {
|
||||
default = true;
|
||||
internal = true;
|
||||
};
|
||||
enableValidation = lib.mkEnableOption ''
|
||||
the validation of bootspec documents for each build.
|
||||
This will introduce Go in the build-time closure as we are relying on [Cuelang](https://cuelang.org/) for schema validation.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ let
|
|||
|
||||
printf "%s " "''${extraDependencies[@]}" > "$out/extra-dependencies"
|
||||
|
||||
${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) ''
|
||||
${optionalString (!config.boot.isContainer) ''
|
||||
${config.boot.bootspec.writer}
|
||||
${optionalString config.boot.bootspec.enableValidation ''${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}"''}
|
||||
''}
|
||||
|
|
@ -139,8 +139,8 @@ in
|
|||
|
||||
system.boot.loader.kernelFile = mkOption {
|
||||
internal = true;
|
||||
default = pkgs.stdenv.hostPlatform.linux-kernel.target;
|
||||
defaultText = literalExpression "pkgs.stdenv.hostPlatform.linux-kernel.target";
|
||||
default = config.boot.kernelPackages.kernel.target;
|
||||
defaultText = literalExpression "config.boot.kernelPackages.kernel.target";
|
||||
type = types.str;
|
||||
description = ''
|
||||
Name of the kernel file to be passed to the bootloader.
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ in
|
|||
|
||||
system.build.installBootLoader = generationsDirBuilder;
|
||||
system.boot.loader.id = "generationsDir";
|
||||
system.boot.loader.kernelFile = pkgs.stdenv.hostPlatform.linux-kernel.target;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -503,7 +503,9 @@ in
|
|||
|
||||
script = ''
|
||||
fwupd_efi=(${config.services.fwupd.package.fwupd-efi}/libexec/fwupd/efi/fwupd*.efi)
|
||||
${lib.getExe cfg.secureBoot.sbctl} sign -o /run/fwupd-efi/$(basename "$fwupd_efi").signed "$fwupd_efi"
|
||||
for efi in "''${fwupd_efi[@]}"; do
|
||||
${lib.getExe cfg.secureBoot.sbctl} sign -o "/run/fwupd-efi/$(basename "$efi").signed" "$efi"
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ NIXOS_DIR = Path(
|
|||
TIMEOUT = "@timeout@"
|
||||
EDITOR = "@editor@" == "1" # noqa: PLR0133
|
||||
CONSOLE_MODE = "@consoleMode@"
|
||||
BOOTSPEC_TOOLS = "@bootspecTools@"
|
||||
DISTRO_NAME = "@distroName@"
|
||||
NIX = "@nix@"
|
||||
SYSTEMD = "@systemd@"
|
||||
|
|
@ -291,31 +290,26 @@ def write_loader_conf(default_entry_id: str | None) -> None:
|
|||
os.rename(tmp, LOADER_CONF)
|
||||
|
||||
|
||||
def get_bootspec(profile: str | None, generation: int) -> BootSpec:
|
||||
def get_bootspec(profile: str | None, generation: int) -> BootSpec | None:
|
||||
system_directory = system_dir(profile, generation, None)
|
||||
boot_json_path = (system_directory / "boot.json").resolve()
|
||||
if boot_json_path.is_file():
|
||||
with boot_json_path.open("r") as f:
|
||||
# check if json is well-formed, else throw error with filepath
|
||||
try:
|
||||
bootspec_json = json.load(f)
|
||||
except ValueError as e:
|
||||
print(
|
||||
f"error: Malformed Json: {e}, in {boot_json_path}", file=sys.stderr
|
||||
)
|
||||
sys.exit(1)
|
||||
else:
|
||||
boot_json_str = run(
|
||||
[
|
||||
f"{BOOTSPEC_TOOLS}/bin/synthesize",
|
||||
"--version",
|
||||
"1",
|
||||
system_directory,
|
||||
"/dev/stdout",
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout
|
||||
bootspec_json = json.loads(boot_json_str)
|
||||
if not boot_json_path.is_file():
|
||||
print(
|
||||
f"warning: skipping generation {generation}"
|
||||
+ (f" of profile {profile}" if profile else "")
|
||||
+ f": {boot_json_path} does not exist",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return None
|
||||
with boot_json_path.open("r") as f:
|
||||
# check if json is well-formed, else throw error with filepath
|
||||
try:
|
||||
bootspec_json = json.load(f)
|
||||
except ValueError as e:
|
||||
print(
|
||||
f"error: Malformed Json: {e}, in {boot_json_path}", file=sys.stderr
|
||||
)
|
||||
sys.exit(1)
|
||||
return bootspec_from_json(bootspec_json)
|
||||
|
||||
|
||||
|
|
@ -551,6 +545,8 @@ def install_bootloader(args: argparse.Namespace) -> None:
|
|||
|
||||
for gen in gens:
|
||||
bootspec = get_bootspec(gen.profile, gen.generation)
|
||||
if bootspec is None:
|
||||
continue
|
||||
is_default = Path(bootspec.init).parent == default_config
|
||||
new_boot_files, new_bootctl_id = boot_file(*gen, machine_id, bootspec)
|
||||
boot_files.extend(new_boot_files)
|
||||
|
|
|
|||
|
|
@ -47,8 +47,6 @@ let
|
|||
|
||||
systemd = config.systemd.package;
|
||||
|
||||
bootspecTools = config.boot.bootspec.package;
|
||||
|
||||
nix = config.nix.package.out;
|
||||
|
||||
timeout = if config.boot.loader.timeout == null then "menu-force" else config.boot.loader.timeout;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ let
|
|||
"network-online.target"
|
||||
"nss-lookup.target"
|
||||
"nss-user-lookup.target"
|
||||
"time-set.target"
|
||||
"time-sync.target"
|
||||
"first-boot-complete.target"
|
||||
]
|
||||
|
|
@ -808,7 +809,7 @@ in
|
|||
systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
|
||||
systemd.services.systemd-importd = lib.mkIf cfg.package.withImportd {
|
||||
environment = proxy_env;
|
||||
path = [ pkgs.gnupg ];
|
||||
path = [ pkgs.gnupgMinimal ];
|
||||
};
|
||||
systemd.services.systemd-pstore.wantedBy = [ "sysinit.target" ]; # see #81138
|
||||
|
||||
|
|
|
|||
|
|
@ -64,13 +64,13 @@
|
|||
environment.etc."systemd/logind.conf".text =
|
||||
utils.systemdUtils.lib.settingsToSections config.services.logind.settings;
|
||||
|
||||
# Restarting systemd-logind breaks X11
|
||||
# Restarting systemd-logind breaks X11 and other user sessions.
|
||||
# However, reloading the service seems to do the trick of loading new configuration without breaking anything.
|
||||
# - upstream commit: https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101
|
||||
# - systemd announcement: https://github.com/systemd/systemd/blob/22043e4317ecd2bc7834b48a6d364de76bb26d91/NEWS#L103-L112
|
||||
# - this might be addressed in the future by xorg
|
||||
#systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
|
||||
systemd.services.systemd-logind.restartIfChanged = false;
|
||||
systemd.services.systemd-logind.stopIfChanged = false;
|
||||
systemd.services.systemd-logind.reloadIfChanged = true;
|
||||
|
||||
# The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions.
|
||||
systemd.services."user-runtime-dir@".stopIfChanged = false;
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ in
|
|||
|
||||
systemd.services.systemd-sysupdated = {
|
||||
aliases = [ "dbus-org.freedesktop.sysupdate1.service" ];
|
||||
path = [ pkgs.gnupg ];
|
||||
path = [ pkgs.gnupgMinimal ];
|
||||
};
|
||||
|
||||
systemd.timers = {
|
||||
|
|
|
|||
|
|
@ -5,16 +5,13 @@
|
|||
utils,
|
||||
...
|
||||
}:
|
||||
with utils;
|
||||
with systemdUtils.unitOptions;
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.systemd.user;
|
||||
|
||||
systemd = config.systemd.package;
|
||||
|
||||
inherit (systemdUtils.lib)
|
||||
inherit (utils.systemdUtils.lib)
|
||||
generateUnits
|
||||
targetToUnit
|
||||
serviceToUnit
|
||||
|
|
@ -53,7 +50,7 @@ let
|
|||
user ? null,
|
||||
}:
|
||||
let
|
||||
suffix = optionalString (user != null) "-${user}";
|
||||
suffix = lib.optionalString (user != null) "-${user}";
|
||||
in
|
||||
pkgs.writeTextFile {
|
||||
name = "nixos-user-tmpfiles.d${suffix}";
|
||||
|
|
@ -61,74 +58,86 @@ let
|
|||
text = ''
|
||||
# This file is created automatically and should not be modified.
|
||||
# Please change the options ‘systemd.user.tmpfiles’ instead.
|
||||
${concatStringsSep "\n" rules}
|
||||
${lib.concatStringsSep "\n" rules}
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [
|
||||
"systemd"
|
||||
"user"
|
||||
"extraConfig"
|
||||
] "Use systemd.user.settings.Manager instead.")
|
||||
];
|
||||
|
||||
options = {
|
||||
systemd.user.extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
example = "DefaultTimeoutStartSec=60";
|
||||
systemd.user.settings.Manager = lib.mkOption {
|
||||
default = { };
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption;
|
||||
};
|
||||
example = {
|
||||
DefaultTimeoutStartSec = 60;
|
||||
};
|
||||
description = ''
|
||||
Extra config options for systemd user instances. See {manpage}`systemd-user.conf(5)` for
|
||||
available options.
|
||||
Settings for systemd user instances. See {manpage}`systemd-user.conf(5)`
|
||||
for available options.
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.user.units = mkOption {
|
||||
systemd.user.units = lib.mkOption {
|
||||
description = "Definition of systemd per-user units.";
|
||||
default = { };
|
||||
type = systemdUtils.types.units;
|
||||
type = utils.systemdUtils.types.units;
|
||||
};
|
||||
|
||||
systemd.user.paths = mkOption {
|
||||
systemd.user.paths = lib.mkOption {
|
||||
default = { };
|
||||
type = systemdUtils.types.paths;
|
||||
type = utils.systemdUtils.types.paths;
|
||||
description = "Definition of systemd per-user path units.";
|
||||
};
|
||||
|
||||
systemd.user.services = mkOption {
|
||||
systemd.user.services = lib.mkOption {
|
||||
default = { };
|
||||
type = systemdUtils.types.services;
|
||||
type = utils.systemdUtils.types.services;
|
||||
description = "Definition of systemd per-user service units.";
|
||||
};
|
||||
|
||||
systemd.user.slices = mkOption {
|
||||
systemd.user.slices = lib.mkOption {
|
||||
default = { };
|
||||
type = systemdUtils.types.slices;
|
||||
type = utils.systemdUtils.types.slices;
|
||||
description = "Definition of systemd per-user slice units.";
|
||||
};
|
||||
|
||||
systemd.user.sockets = mkOption {
|
||||
systemd.user.sockets = lib.mkOption {
|
||||
default = { };
|
||||
type = systemdUtils.types.sockets;
|
||||
type = utils.systemdUtils.types.sockets;
|
||||
description = "Definition of systemd per-user socket units.";
|
||||
};
|
||||
|
||||
systemd.user.targets = mkOption {
|
||||
systemd.user.targets = lib.mkOption {
|
||||
default = { };
|
||||
type = systemdUtils.types.targets;
|
||||
type = utils.systemdUtils.types.targets;
|
||||
description = "Definition of systemd per-user target units.";
|
||||
};
|
||||
|
||||
systemd.user.timers = mkOption {
|
||||
systemd.user.timers = lib.mkOption {
|
||||
default = { };
|
||||
type = systemdUtils.types.timers;
|
||||
type = utils.systemdUtils.types.timers;
|
||||
description = "Definition of systemd per-user timer units.";
|
||||
};
|
||||
|
||||
systemd.user.tmpfiles = {
|
||||
enable =
|
||||
(mkEnableOption "systemd user units systemd-tmpfiles-setup.service and systemd-tmpfiles-clean.timer")
|
||||
(lib.mkEnableOption "systemd user units systemd-tmpfiles-setup.service and systemd-tmpfiles-clean.timer")
|
||||
// {
|
||||
default = true;
|
||||
example = false;
|
||||
};
|
||||
|
||||
rules = mkOption {
|
||||
type = types.listOf types.str;
|
||||
rules = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [ "D %C - - - 7d" ];
|
||||
description = ''
|
||||
|
|
@ -139,17 +148,17 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
users = mkOption {
|
||||
users = lib.mkOption {
|
||||
description = ''
|
||||
Per-user rules for creation, deletion and cleaning of volatile and
|
||||
temporary files automatically.
|
||||
'';
|
||||
default = { };
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
rules = mkOption {
|
||||
type = types.listOf types.str;
|
||||
rules = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [ "D %C - - - 7d" ];
|
||||
description = ''
|
||||
|
|
@ -165,8 +174,8 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
systemd.user.generators = mkOption {
|
||||
type = types.attrsOf types.path;
|
||||
systemd.user.generators = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.path;
|
||||
default = { };
|
||||
example = {
|
||||
systemd-gpt-auto-generator = "/dev/null";
|
||||
|
|
@ -179,9 +188,9 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
systemd.additionalUpstreamUserUnits = mkOption {
|
||||
systemd.additionalUpstreamUserUnits = lib.mkOption {
|
||||
default = [ ];
|
||||
type = types.listOf types.str;
|
||||
type = lib.types.listOf lib.types.str;
|
||||
example = [ ];
|
||||
description = ''
|
||||
Additional units shipped with systemd that should be enabled for per-user systemd instances.
|
||||
|
|
@ -203,29 +212,26 @@ in
|
|||
upstreamWants = [ ];
|
||||
};
|
||||
|
||||
"systemd/user.conf".text = ''
|
||||
[Manager]
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
"systemd/user.conf".text = utils.systemdUtils.lib.settingsToSections cfg.settings;
|
||||
};
|
||||
|
||||
systemd.user.units =
|
||||
mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit v)) cfg.paths
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit v)) cfg.services
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit v)) cfg.targets
|
||||
// mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers;
|
||||
lib.mapAttrs' (n: v: lib.nameValuePair "${n}.path" (pathToUnit v)) cfg.paths
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.service" (serviceToUnit v)) cfg.services
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.target" (targetToUnit v)) cfg.targets
|
||||
// lib.mapAttrs' (n: v: lib.nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers;
|
||||
|
||||
systemd.user.timers = {
|
||||
# enable systemd user tmpfiles
|
||||
systemd-tmpfiles-clean.wantedBy = optional cfg.tmpfiles.enable "timers.target";
|
||||
systemd-tmpfiles-clean.wantedBy = lib.optional cfg.tmpfiles.enable "timers.target";
|
||||
}
|
||||
# Generate timer units for all services that have a ‘startAt’ value.
|
||||
// (mapAttrs (name: service: {
|
||||
// (lib.mapAttrs (name: service: {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig.OnCalendar = service.startAt;
|
||||
}) (filterAttrs (name: service: service.startAt != [ ]) cfg.services));
|
||||
}) (lib.filterAttrs (name: service: service.startAt != [ ]) cfg.services));
|
||||
|
||||
# Provide the systemd-user PAM service, required to run systemd
|
||||
# user instances.
|
||||
|
|
@ -244,18 +250,19 @@ in
|
|||
systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
|
||||
|
||||
# enable systemd user tmpfiles
|
||||
systemd.user.services.systemd-tmpfiles-setup.wantedBy = optional cfg.tmpfiles.enable "basic.target";
|
||||
systemd.user.services.systemd-tmpfiles-setup.wantedBy =
|
||||
lib.optional cfg.tmpfiles.enable "basic.target";
|
||||
|
||||
# /run/current-system/sw/etc/xdg is in systemd's $XDG_CONFIG_DIRS so we can
|
||||
# write the tmpfiles.d rules for everyone there
|
||||
environment.systemPackages = optional (cfg.tmpfiles.rules != [ ]) (writeTmpfiles {
|
||||
environment.systemPackages = lib.optional (cfg.tmpfiles.rules != [ ]) (writeTmpfiles {
|
||||
inherit (cfg.tmpfiles) rules;
|
||||
});
|
||||
|
||||
# /etc/profiles/per-user/$USER/etc/xdg is in systemd's $XDG_CONFIG_DIRS so
|
||||
# we can write a single user's tmpfiles.d rules there
|
||||
users.users = mapAttrs (user: cfg': {
|
||||
packages = optional (cfg'.rules != [ ]) (writeTmpfiles {
|
||||
users.users = lib.mapAttrs (user: cfg': {
|
||||
packages = lib.optional (cfg'.rules != [ ]) (writeTmpfiles {
|
||||
inherit (cfg') rules;
|
||||
inherit user;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -238,11 +238,11 @@ in
|
|||
'';
|
||||
|
||||
systemd.settings.Manager = managerSettings;
|
||||
systemd.user.extraConfig = ''
|
||||
systemd.user.settings.Manager = {
|
||||
# Allow very slow start
|
||||
DefaultTimeoutStartSec=300
|
||||
DefaultDeviceTimeoutSec=300
|
||||
'';
|
||||
DefaultTimeoutStartSec = 300;
|
||||
DefaultDeviceTimeoutSec = 300;
|
||||
};
|
||||
|
||||
boot.consoleLogLevel = 7;
|
||||
|
||||
|
|
|
|||
|
|
@ -1307,6 +1307,8 @@ in
|
|||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = lib.mkIf (config.nix.daemonUser != "root") config.nix.daemonUser;
|
||||
Group = lib.mkIf (config.nix.daemonGroup != "root") config.nix.daemonGroup;
|
||||
};
|
||||
script = ''
|
||||
if [[ "$(cat /proc/cmdline)" =~ regInfo=([^ ]*) ]]; then
|
||||
|
|
@ -1379,7 +1381,6 @@ in
|
|||
"-device usb-tablet,bus=usb-bus.0"
|
||||
])
|
||||
(mkIf pkgs.stdenv.hostPlatform.isAarch [
|
||||
"-device virtio-gpu-pci"
|
||||
"-device usb-ehci,id=usb0"
|
||||
"-device usb-kbd"
|
||||
"-device usb-tablet"
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ let
|
|||
tarball
|
||||
// {
|
||||
meta = {
|
||||
description = "NixOS system tarball for ${system} - ${stdenv.hostPlatform.linux-kernel.name}";
|
||||
description = "NixOS system tarball for ${system}";
|
||||
maintainers = map (x: lib.maintainers.${x}) maintainers;
|
||||
};
|
||||
inherit config;
|
||||
|
|
@ -188,7 +188,7 @@ let
|
|||
modules = makeModules module { };
|
||||
};
|
||||
build = configEvaled.config.system.build;
|
||||
kernelTarget = configEvaled.pkgs.stdenv.hostPlatform.linux-kernel.target;
|
||||
kernelTarget = build.kernel.target;
|
||||
in
|
||||
configEvaled.pkgs.symlinkJoin {
|
||||
name = "netboot";
|
||||
|
|
|
|||
|
|
@ -695,6 +695,7 @@ in
|
|||
grocy = runTest ./grocy.nix;
|
||||
grow-partition = runTest ./grow-partition.nix;
|
||||
grub = runTest ./grub.nix;
|
||||
gs1200-exporter = runTest ./gs1200-exporter.nix;
|
||||
guacamole-server = runTest ./guacamole-server.nix;
|
||||
guix = handleTest ./guix { };
|
||||
gvisor = runTest ./gvisor.nix;
|
||||
|
|
@ -1489,11 +1490,13 @@ in
|
|||
sane = runTest ./sane.nix;
|
||||
sanoid = runTest ./sanoid.nix;
|
||||
saunafs = runTest ./saunafs.nix;
|
||||
scanservjs = runTest ./scanservjs.nix;
|
||||
scaphandre = runTest ./scaphandre.nix;
|
||||
schleuder = runTest ./schleuder.nix;
|
||||
scion-freestanding-deployment = runTest ./scion/freestanding-deployment;
|
||||
scrutiny = runTest ./scrutiny.nix;
|
||||
scx = runTest ./scx/default.nix;
|
||||
scx-loader = runTest ./scx/loader.nix;
|
||||
sddm = import ./sddm.nix { inherit runTest; };
|
||||
sdl3 = runTest ./sdl3.nix;
|
||||
searx = runTest ./searx.nix;
|
||||
|
|
@ -1670,6 +1673,7 @@ in
|
|||
systemd-timesyncd-nscd-dnssec = runTest ./systemd-timesyncd-nscd-dnssec.nix;
|
||||
systemd-user-linger = runTest ./systemd-user-linger.nix;
|
||||
systemd-user-linger-purge = runTest ./systemd-user-linger-purge.nix;
|
||||
systemd-user-settings = runTest ./systemd-user-settings.nix;
|
||||
systemd-user-tmpfiles-rules = runTest ./systemd-user-tmpfiles-rules.nix;
|
||||
systemd-userdbd = runTest ./systemd-userdbd.nix;
|
||||
systemtap = handleTest ./systemtap.nix { };
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ let
|
|||
environment.systemPackages = [ pkgs.efibootmgr ];
|
||||
};
|
||||
standard = {
|
||||
boot.bootspec.enable = true;
|
||||
|
||||
imports = [
|
||||
baseline
|
||||
systemd-boot
|
||||
|
|
@ -53,8 +51,6 @@ in
|
|||
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||
|
||||
nodes.machine = {
|
||||
boot.bootspec.enable = true;
|
||||
|
||||
imports = [
|
||||
baseline
|
||||
grub
|
||||
|
|
@ -75,8 +71,6 @@ in
|
|||
meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
|
||||
|
||||
nodes.machine = {
|
||||
boot.bootspec.enable = true;
|
||||
|
||||
imports = [
|
||||
baseline
|
||||
grub
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
alias Domain.{Repo, Accounts, Auth, Actors, Tokens}
|
||||
|
||||
mappings = case File.read("provision-uuids.json") do
|
||||
{:ok, content} ->
|
||||
case Jason.decode(content) do
|
||||
{:ok, mapping} -> mapping
|
||||
_ -> %{"accounts" => %{}}
|
||||
end
|
||||
_ -> %{"accounts" => %{}}
|
||||
end
|
||||
|
||||
IO.puts("INFO: Fetching account")
|
||||
{:ok, account} = Accounts.fetch_account_by_id_or_slug("main")
|
||||
|
||||
IO.puts("INFO: Fetching email provider")
|
||||
{:ok, email_provider} = Auth.Provider.Query.not_disabled()
|
||||
|> Auth.Provider.Query.by_adapter(:email)
|
||||
|> Auth.Provider.Query.by_account_id(account.id)
|
||||
|> Repo.fetch(Auth.Provider.Query, [])
|
||||
|
||||
temp_admin_actor_email = "firezone-provision@localhost.local"
|
||||
temp_admin_actor_context = %Auth.Context{
|
||||
type: :browser,
|
||||
user_agent: "Unspecified/0.0",
|
||||
remote_ip: {127, 0, 0, 1},
|
||||
remote_ip_location_region: "N/A",
|
||||
remote_ip_location_city: "N/A",
|
||||
remote_ip_location_lat: 0.0,
|
||||
remote_ip_location_lon: 0.0
|
||||
}
|
||||
|
||||
{:ok, temp_admin_actor} =
|
||||
Actors.create_actor(account, %{
|
||||
type: :account_admin_user,
|
||||
name: "Token Provisioning"
|
||||
})
|
||||
|
||||
{:ok, temp_admin_actor_email_identity} =
|
||||
Auth.create_identity(temp_admin_actor, email_provider, %{
|
||||
provider_identifier: temp_admin_actor_email,
|
||||
provider_identifier_confirmation: temp_admin_actor_email
|
||||
})
|
||||
|
||||
{:ok, temp_admin_actor_token} =
|
||||
Auth.create_token(temp_admin_actor_email_identity, temp_admin_actor_context, "temporarynonce", DateTime.utc_now() |> DateTime.add(1, :hour))
|
||||
|
||||
{:ok, temp_admin_subject} =
|
||||
Auth.build_subject(temp_admin_actor_token, temp_admin_actor_context)
|
||||
|
||||
{:ok, relay_group_token} =
|
||||
Tokens.create_token(%{
|
||||
"type" => :relay_group,
|
||||
"expires_at" => DateTime.utc_now() |> DateTime.add(1, :hour),
|
||||
"secret_fragment" => Domain.Crypto.random_token(32, encoder: :hex32),
|
||||
"relay_group_id" => get_in(mappings, ["accounts", "main", "relay_groups", "my-relays"])
|
||||
})
|
||||
|
||||
relay_group_encoded_token = Tokens.encode_fragment!(relay_group_token)
|
||||
IO.puts("Created relay token: #{relay_group_encoded_token}")
|
||||
File.write("relay_token.txt", relay_group_encoded_token)
|
||||
|
||||
{:ok, gateway_group_token} =
|
||||
Tokens.create_token(%{
|
||||
"type" => :gateway_group,
|
||||
"expires_at" => DateTime.utc_now() |> DateTime.add(1, :hour),
|
||||
"secret_fragment" => Domain.Crypto.random_token(32, encoder: :hex32),
|
||||
"account_id" => get_in(mappings, ["accounts", "main", "id"]),
|
||||
"gateway_group_id" => get_in(mappings, ["accounts", "main", "gateway_groups", "site"])
|
||||
}, temp_admin_subject)
|
||||
|
||||
gateway_group_encoded_token = Tokens.encode_fragment!(gateway_group_token)
|
||||
IO.puts("Created gateway group token: #{gateway_group_encoded_token}")
|
||||
File.write("gateway_token.txt", gateway_group_encoded_token)
|
||||
|
||||
{:ok, service_account_actor_token} =
|
||||
Tokens.create_token(%{
|
||||
"type" => :client,
|
||||
"expires_at" => DateTime.utc_now() |> DateTime.add(1, :hour),
|
||||
"secret_fragment" => Domain.Crypto.random_token(32, encoder: :hex32),
|
||||
"account_id" => get_in(mappings, ["accounts", "main", "id"]),
|
||||
"actor_id" => get_in(mappings, ["accounts", "main", "actors", "client"])
|
||||
})
|
||||
|
||||
service_account_actor_encoded_token = Tokens.encode_fragment!(service_account_actor_token)
|
||||
IO.puts("Created service actor token: #{service_account_actor_encoded_token}")
|
||||
File.write("client_token.txt", service_account_actor_encoded_token)
|
||||
|
|
@ -84,89 +84,15 @@ in
|
|||
passwordFile = pkgs.writeText "tmpmailpasswd" "verysecurepassword";
|
||||
};
|
||||
|
||||
provision = {
|
||||
enable = true;
|
||||
accounts.main = {
|
||||
name = "My Account";
|
||||
relayGroups.my-relays.name = "Relays";
|
||||
gatewayGroups.site.name = "Site";
|
||||
actors = {
|
||||
admin = {
|
||||
type = "account_admin_user";
|
||||
name = "Admin";
|
||||
email = "admin@localhost.localdomain";
|
||||
};
|
||||
client = {
|
||||
type = "service_account";
|
||||
name = "A client";
|
||||
email = "client@example.com";
|
||||
};
|
||||
};
|
||||
# service accounts aren't members of 'Everyone' so we need to add a separate group
|
||||
groups.main = {
|
||||
name = "main";
|
||||
members = [
|
||||
"client"
|
||||
"admin"
|
||||
];
|
||||
};
|
||||
resources.res1 = {
|
||||
type = "dns";
|
||||
name = "Dns Resource";
|
||||
address = "resource.example.com";
|
||||
gatewayGroups = [ "site" ];
|
||||
filters = [
|
||||
{ protocol = "icmp"; }
|
||||
{
|
||||
protocol = "tcp";
|
||||
ports = [ 80 ];
|
||||
}
|
||||
];
|
||||
};
|
||||
resources.res2 = {
|
||||
type = "ip";
|
||||
name = "Ip Resource";
|
||||
address = "172.20.2.1";
|
||||
gatewayGroups = [ "site" ];
|
||||
};
|
||||
resources.res3 = {
|
||||
type = "cidr";
|
||||
name = "Cidr Resource";
|
||||
address = "172.20.1.0/24";
|
||||
gatewayGroups = [ "site" ];
|
||||
};
|
||||
policies.pol1 = {
|
||||
description = "Allow anyone res1 access";
|
||||
group = "main";
|
||||
resource = "res1";
|
||||
};
|
||||
policies.pol2 = {
|
||||
description = "Allow anyone res2 access";
|
||||
group = "main";
|
||||
resource = "res2";
|
||||
};
|
||||
policies.pol3 = {
|
||||
description = "Allow anyone res3 access";
|
||||
group = "main";
|
||||
resource = "res3";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
api.externalUrl = "https://${domain}/api/";
|
||||
web.externalUrl = "https://${domain}/";
|
||||
};
|
||||
|
||||
systemd.services.firezone-server-domain.postStart = lib.mkAfter ''
|
||||
${lib.getExe config.services.firezone.server.domain.package} rpc 'Code.eval_file("${./create-tokens.exs}")'
|
||||
'';
|
||||
};
|
||||
|
||||
relay =
|
||||
{
|
||||
nodes,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
|
|
@ -181,14 +107,11 @@ in
|
|||
logLevel = "debug";
|
||||
name = "test-relay";
|
||||
apiUrl = "wss://${domain}/api/";
|
||||
tokenFile = "/tmp/shared/relay_token.txt";
|
||||
tokenFile = pkgs.writeText "token" "token";
|
||||
publicIpv4 = config.networking.primaryIPAddress;
|
||||
publicIpv6 = config.networking.primaryIPv6Address;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
# Don't auto-start so we can wait until the token was provisioned
|
||||
systemd.services.firezone-relay.wantedBy = lib.mkForce [ ];
|
||||
};
|
||||
|
||||
# A resource that is only connected to the gateway,
|
||||
|
|
@ -300,11 +223,8 @@ in
|
|||
logLevel = "debug";
|
||||
name = "test-gateway";
|
||||
apiUrl = "wss://${domain}/api/";
|
||||
tokenFile = "/tmp/shared/gateway_token.txt";
|
||||
tokenFile = pkgs.writeText "token" "token";
|
||||
};
|
||||
|
||||
# Don't auto-start so we can wait until the token was provisioned
|
||||
systemd.services.firezone-gateway.wantedBy = lib.mkForce [ ];
|
||||
};
|
||||
|
||||
client =
|
||||
|
|
@ -326,11 +246,8 @@ in
|
|||
logLevel = "debug";
|
||||
name = "test-client-somebody";
|
||||
apiUrl = "wss://${domain}/api/";
|
||||
tokenFile = "/tmp/shared/client_token.txt";
|
||||
tokenFile = pkgs.writeText "token" "token";
|
||||
};
|
||||
|
||||
# Don't auto-start so we can wait until the token was provisioned
|
||||
systemd.services.firezone-headless-client.wantedBy = lib.mkForce [ ];
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -344,43 +261,13 @@ in
|
|||
server.wait_until_succeeds("curl -Lsf https://${domain} | grep 'Welcome to Firezone'")
|
||||
server.wait_until_succeeds("curl -Ls https://${domain}/api | grep 'Not Found'")
|
||||
|
||||
# Wait for tokens and copy them to shared folder
|
||||
server.wait_for_file("/var/lib/private/firezone/relay_token.txt")
|
||||
server.wait_for_file("/var/lib/private/firezone/gateway_token.txt")
|
||||
server.wait_for_file("/var/lib/private/firezone/client_token.txt")
|
||||
server.succeed("cp /var/lib/private/firezone/*_token.txt /tmp/shared")
|
||||
|
||||
with subtest("Connect relay"):
|
||||
relay.succeed("systemctl start firezone-relay")
|
||||
relay.wait_for_unit("firezone-relay.service")
|
||||
relay.wait_until_succeeds("journalctl --since -2m --unit firezone-relay.service --grep 'Connected to portal.*${domain}'", timeout=30)
|
||||
|
||||
with subtest("Connect gateway"):
|
||||
gateway.succeed("systemctl start firezone-gateway")
|
||||
gateway.wait_for_unit("firezone-gateway.service")
|
||||
gateway.wait_until_succeeds("journalctl --since -2m --unit firezone-gateway.service --grep 'Connected to portal.*${domain}'", timeout=30)
|
||||
relay.wait_until_succeeds("journalctl --since -2m --unit firezone-relay.service --grep 'Created allocation.*IPv4'", timeout=30)
|
||||
relay.wait_until_succeeds("journalctl --since -2m --unit firezone-relay.service --grep 'Created allocation.*IPv6'", timeout=30)
|
||||
|
||||
# Assert both relay ips are known
|
||||
gateway.wait_until_succeeds("journalctl --since -2m --unit firezone-gateway.service --grep 'Updated allocation.*relay_ip4.*Some.*relay_ip6.*Some'", timeout=30)
|
||||
|
||||
with subtest("Connect headless-client"):
|
||||
client.succeed("systemctl start firezone-headless-client")
|
||||
client.wait_for_unit("firezone-headless-client.service")
|
||||
client.wait_until_succeeds("journalctl --since -2m --unit firezone-headless-client.service --grep 'Connected to portal.*${domain}'", timeout=30)
|
||||
client.wait_until_succeeds("journalctl --since -2m --unit firezone-headless-client.service --grep 'Tunnel ready'", timeout=30)
|
||||
|
||||
with subtest("Check DNS based access"):
|
||||
# Check that we can access the resource through the VPN via DNS
|
||||
client.wait_until_succeeds("curl -4 -Lsf http://resource.example.com | grep 'greetings from the resource'")
|
||||
|
||||
with subtest("Check CIDR based access"):
|
||||
# Check that we can access the resource through the VPN via CIDR
|
||||
client.wait_until_succeeds("ping -c1 -W1 172.20.1.1")
|
||||
|
||||
with subtest("Check IP based access"):
|
||||
# Check that we can access the resource through the VPN via IP
|
||||
client.wait_until_succeeds("ping -c1 -W1 172.20.2.1")
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
20
nixos/tests/gs1200-exporter.nix
Normal file
20
nixos/tests/gs1200-exporter.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{ lib, ... }:
|
||||
{
|
||||
name = "gs1200-exporter";
|
||||
meta.maintainers = with lib.maintainers; [ DerGrumpf ];
|
||||
nodes.machine = _: {
|
||||
services.gs1200-exporter = {
|
||||
enable = true;
|
||||
address = "192.168.2.4";
|
||||
passwordFile = "/run/secrets/gs1200-password";
|
||||
};
|
||||
systemd.tmpfiles.rules = [
|
||||
"f /run/secrets/gs1200-password 0400 root root - testpassword"
|
||||
];
|
||||
};
|
||||
testScript = ''
|
||||
machine.wait_for_unit("gs1200-exporter.service")
|
||||
machine.wait_for_open_port(9934)
|
||||
machine.succeed("curl -f http://localhost:9934/metrics")
|
||||
'';
|
||||
}
|
||||
|
|
@ -793,7 +793,6 @@ let
|
|||
++ optionals (bootLoader == "systemd-boot") [
|
||||
pkgs.zstd.bin
|
||||
pkgs.mypy
|
||||
config.boot.bootspec.package
|
||||
]
|
||||
++ optionals clevisTest [ pkgs.klibc ]
|
||||
++ optional systemdStage1 config.system.nixos-init.package;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
{ pkgs, lib, ... }:
|
||||
let
|
||||
# opensnitch ebpf seems to handle non-x86 syscalls incorrectly
|
||||
test_ebpf = pkgs.stdenv.hostPlatform.isx86;
|
||||
|
||||
monitorMethods = [
|
||||
"ebpf"
|
||||
"proc"
|
||||
"ftrace"
|
||||
"audit"
|
||||
];
|
||||
]
|
||||
++ lib.optional test_ebpf "ebpf";
|
||||
in
|
||||
{
|
||||
name = "opensnitch";
|
||||
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ onny ];
|
||||
maintainers = [
|
||||
onny
|
||||
grimmauld
|
||||
];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
|
|
@ -88,13 +94,13 @@ in
|
|||
lib.concatLines (
|
||||
map (m: ''
|
||||
client_blocked_${m}.wait_for_unit("opensnitchd.service")
|
||||
client_blocked_${m}.fail("curl http://server")
|
||||
client_blocked_${m}.fail("curl --connect-timeout 3 http://server")
|
||||
|
||||
client_allowed_${m}.wait_for_unit("opensnitchd.service")
|
||||
client_allowed_${m}.succeed("curl http://server")
|
||||
client_allowed_${m}.succeed("curl --connect-timeout 3 http://server")
|
||||
'') monitorMethods
|
||||
)
|
||||
+ ''
|
||||
+ lib.optionalString test_ebpf ''
|
||||
# make sure the kernel modules were actually properly loaded
|
||||
client_blocked_ebpf.succeed(r"journalctl -u opensnitchd --grep '\[eBPF\] module loaded: /nix/store/.*/etc/opensnitchd/opensnitch\.o'")
|
||||
client_blocked_ebpf.succeed(r"journalctl -u opensnitchd --grep '\[eBPF\] module loaded: /nix/store/.*/etc/opensnitchd/opensnitch-procs\.o'")
|
||||
|
|
|
|||
23
nixos/tests/scanservjs.nix
Normal file
23
nixos/tests/scanservjs.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
let
|
||||
port = 1234;
|
||||
in
|
||||
{
|
||||
name = "scanservjs";
|
||||
|
||||
nodes.machine =
|
||||
{ ... }:
|
||||
{
|
||||
services.scanservjs = {
|
||||
enable = true;
|
||||
settings.host = "0.0.0.0";
|
||||
settings.port = port;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("scanservjs.service")
|
||||
machine.wait_until_succeeds(
|
||||
"curl --silent --fail --show-error --location http://localhost:${toString port}"
|
||||
)
|
||||
'';
|
||||
}
|
||||
20
nixos/tests/scx/loader.nix
Normal file
20
nixos/tests/scx/loader.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{ pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
name = "scx-loader";
|
||||
meta.maintainers = with lib.maintainers; [ ccicnce113424 ];
|
||||
|
||||
nodes.machine = {
|
||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
services.scx-loader = {
|
||||
enable = true;
|
||||
config.default_sched = "scx_bpfland";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
output = machine.succeed("scxctl get").strip()
|
||||
assert output == "running Bpfland in Auto mode", f"Unexpected scxctl output: {output!r}"
|
||||
'';
|
||||
}
|
||||
|
|
@ -88,6 +88,9 @@
|
|||
|
||||
machine.succeed("shadps4 /etc/openorbis-sample-packages/OpenOrbis-PNG-Sample/uroot/eboot.bin >&2 &")
|
||||
|
||||
machine.wait_for_text("Save Migration")
|
||||
machine.succeed("xdotool mousemove 879 182 click 1")
|
||||
|
||||
# Look for logo
|
||||
with machine.nested("Waiting for the screen to have openorbisColor {} on it:".format(openorbisColor)):
|
||||
retry(check_for_color(openorbisColor))
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ in
|
|||
meta = {
|
||||
maintainers = with lib.maintainers; [
|
||||
happysalada
|
||||
euxane
|
||||
onny
|
||||
];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -772,26 +772,6 @@ in
|
|||
}
|
||||
);
|
||||
|
||||
no-bootspec = runTest (
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "systemd-boot-no-bootspec";
|
||||
meta.maintainers = with lib.maintainers; [ julienmalka ];
|
||||
|
||||
nodes.machine = {
|
||||
imports = [ common ];
|
||||
boot.bootspec.enable = false;
|
||||
};
|
||||
|
||||
testScript =
|
||||
# python
|
||||
''
|
||||
machine.start()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
'';
|
||||
}
|
||||
);
|
||||
|
||||
bootCounting =
|
||||
let
|
||||
baseConfig = {
|
||||
|
|
|
|||
24
nixos/tests/systemd-user-settings.nix
Normal file
24
nixos/tests/systemd-user-settings.nix
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
name = "systemd-user-settings";
|
||||
meta = {
|
||||
maintainers = [ ];
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ lib, ... }:
|
||||
{
|
||||
systemd.user.settings.Manager = {
|
||||
DefaultTimeoutStartSec = lib.mkForce "60";
|
||||
DefaultEnvironment = "FOO=bar";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
with subtest("settings.Manager renders user.conf"):
|
||||
machine.succeed("grep -F '[Manager]' /etc/systemd/user.conf")
|
||||
machine.succeed("grep -F 'DefaultTimeoutStartSec=60' /etc/systemd/user.conf")
|
||||
machine.succeed("grep -F 'DefaultEnvironment=FOO=bar' /etc/systemd/user.conf")
|
||||
'';
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
RebootWatchdogSec = "10min";
|
||||
KExecWatchdogSec = "5min";
|
||||
};
|
||||
systemd.user.extraConfig = "DefaultEnvironment=\"XXX_USER=bar\"";
|
||||
systemd.user.settings.Manager.DefaultEnvironment = "\"XXX_USER=bar\"";
|
||||
services.journald.extraConfig = "Storage=volatile";
|
||||
test-support.displayManager.auto.user = "alice";
|
||||
|
||||
|
|
|
|||
|
|
@ -283,18 +283,22 @@ in
|
|||
enable = lib.mkOverride 0 true;
|
||||
userControlled = true;
|
||||
allowAuxiliaryImperativeNetworks = true;
|
||||
interfaces = [ "wlan1" ];
|
||||
interfaces = [
|
||||
"wlan0"
|
||||
"wlan1"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
wpa_cli = "sudo -u alice -g wpa_supplicant wpa_cli"
|
||||
|
||||
with subtest("Daemon is running and accepting connections"):
|
||||
machine.wait_for_unit("wpa_supplicant-wlan1.service")
|
||||
status = machine.wait_until_succeeds(f"{wpa_cli} -i wlan1 status")
|
||||
assert "Failed to connect" not in status, \
|
||||
"Failed to connect to the daemon"
|
||||
with subtest("Daemons are running and accepting connections"):
|
||||
for iface in ["wlan0", "wlan1"]:
|
||||
machine.wait_for_unit(f"wpa_supplicant-{iface}.service")
|
||||
status = machine.wait_until_succeeds(f"{wpa_cli} -i {iface} status")
|
||||
assert "Failed to connect" not in status, \
|
||||
f"Failed to connect to the daemon for {iface}"
|
||||
|
||||
with subtest("Daemon can be configured imperatively"):
|
||||
machine.succeed(f"{wpa_cli} -i wlan1 add_network")
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
client.wait_for_unit("multi-user.target")
|
||||
|
||||
for be in ["fs", "rocksdb", "mem" ]:
|
||||
client.succeed(f"mosquitto_pub -h router -t {be}/test -m hello")
|
||||
client.succeed(f"mosquitto_pub -q 1 -h router -t {be}/test -m hello")
|
||||
client.succeed(f"curl router:8000/{be}/test | grep hello")
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ let
|
|||
inherit tiling_wm;
|
||||
};
|
||||
stableVersion = {
|
||||
version = "2025.3.4.7"; # "Android Studio Panda 4 | 2025.3.4 Patch 1"
|
||||
sha256Hash = "sha256-qujzMvEkr9I8pJXcdwkVpFbadIDI+FngFTWtQvy0ygY=";
|
||||
url = "https://edgedl.me.gvt1.com/android/studio/ide-zips/2025.3.4.7/android-studio-panda4-patch1-linux.tar.gz";
|
||||
version = "2026.1.1.8"; # "Android Studio Quail 1 | 2026.1.1"
|
||||
sha256Hash = "sha256-DB+kujz6vQfkipDgCl+i6iqCzVhwgz2tpbApDIF9g9M=";
|
||||
url = "https://edgedl.me.gvt1.com/android/studio/ide-zips/2026.1.1.8/android-studio-quail1-linux.tar.gz";
|
||||
};
|
||||
betaVersion = {
|
||||
version = "2026.1.1.7"; # "Android Studio Quail 1 | 2026.1.1 RC 2"
|
||||
|
|
|
|||
|
|
@ -408,6 +408,8 @@ stdenv.mkDerivation (finalAttrs: {
|
|||
(lib.withFeature withSelinux "selinux")
|
||||
];
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
env =
|
||||
lib.optionalAttrs withNativeCompilation {
|
||||
NATIVE_FULL_AOT = "1";
|
||||
|
|
|
|||
|
|
@ -12,20 +12,20 @@ let
|
|||
# update-script-start: urls
|
||||
urls = {
|
||||
x86_64-linux = {
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.2.tar.gz";
|
||||
hash = "sha256-xoMOLYSuWqWUh5RLI1Q4OnAgGM6tqRDWd1VoULX17yE=";
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.3.tar.gz";
|
||||
hash = "sha256-lryIoVxoytyDyfgjnobQ3e94wIIohmIKL88fwf2I49w=";
|
||||
};
|
||||
aarch64-linux = {
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.2-aarch64.tar.gz";
|
||||
hash = "sha256-Qe9yclQj971jK8V2SL5GAlNpgUfTwP/PS2ILv2LyhuE=";
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.3-aarch64.tar.gz";
|
||||
hash = "sha256-oZQaxpVV0O4WlDE6Ia+KzHIF0SfWQBubBFIopSRMbvE=";
|
||||
};
|
||||
x86_64-darwin = {
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.2.dmg";
|
||||
hash = "sha256-DmsOaBjKnhbipSrIfbTqNd9+qcd2i3zkKfVvLK1GXbI=";
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.3.dmg";
|
||||
hash = "sha256-KUcQRWYUD/+4HHWnkGuqoltqL2an0WQkUEfUcttwjCI=";
|
||||
};
|
||||
aarch64-darwin = {
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.2-aarch64.dmg";
|
||||
hash = "sha256-2YyCHi7yPXnq5KWkqC+Uodnc4xj+DkTsL1vUNqLNmPg=";
|
||||
url = "https://download.jetbrains.com/webstorm/WebStorm-2026.1.3-aarch64.dmg";
|
||||
hash = "sha256-1N1RtN1QLvuJ1QL8jbN5TdbOHAHSN84W9XEK2PEPijI=";
|
||||
};
|
||||
};
|
||||
# update-script-end: urls
|
||||
|
|
@ -39,8 +39,8 @@ mkJetBrainsProduct {
|
|||
product = "WebStorm";
|
||||
|
||||
# update-script-start: version
|
||||
version = "2026.1.2";
|
||||
buildNumber = "261.24374.125";
|
||||
version = "2026.1.3";
|
||||
buildNumber = "261.25134.101";
|
||||
# update-script-end: version
|
||||
|
||||
src = fetchurl (urls.${system} or (throw "Unsupported system: ${system}"));
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ self: super: {
|
|||
homepage = "https://github.com/catppuccin/kakoune/";
|
||||
license = lib.licenses.mit;
|
||||
platforms = lib.platforms.all;
|
||||
maintainers = with lib.maintainers; [ philipwilk ];
|
||||
maintainers = with lib.maintainers; [ jadewilk ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -558,4 +558,25 @@ pkgs.lib.recurseIntoAttrs rec {
|
|||
EOF
|
||||
'';
|
||||
};
|
||||
|
||||
nvim_require_check_rtp_no_duplicate = vimUtils.buildVimPlugin {
|
||||
pname = "neovim-require-check-rtp-no-duplicate-test";
|
||||
version = "0";
|
||||
src = runCommandLocal "neovim-require-check-rtp-no-duplicate-src" { } ''
|
||||
mkdir -p "$out/lua/require-check-rtp-dedup"
|
||||
cat > "$out/lua/require-check-rtp-dedup/init.lua" <<'EOF'
|
||||
local target = "lua/require-check-rtp-dedup/init.lua"
|
||||
local matches = vim.api.nvim_get_runtime_file(target, true)
|
||||
if #matches ~= 1 then
|
||||
error(
|
||||
("expected plugin on runtimepath exactly once, found %d:\n%s"):format(
|
||||
#matches,
|
||||
table.concat(matches, "\n")
|
||||
)
|
||||
)
|
||||
end
|
||||
return {}
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
lib,
|
||||
buildPythonApplication,
|
||||
python3Packages,
|
||||
fetchFromGitHub,
|
||||
gdk-pixbuf,
|
||||
glib,
|
||||
|
|
@ -9,12 +9,9 @@
|
|||
gtksourceview,
|
||||
pango,
|
||||
webkitgtk_4_1,
|
||||
pygobject3,
|
||||
pyyaml,
|
||||
setuptools,
|
||||
}:
|
||||
|
||||
buildPythonApplication (finalAttrs: {
|
||||
python3Packages.buildPythonApplication (finalAttrs: {
|
||||
pname = "rednotebook";
|
||||
version = "2.42";
|
||||
pyproject = true;
|
||||
|
|
@ -31,7 +28,7 @@ buildPythonApplication (finalAttrs: {
|
|||
|
||||
nativeBuildInputs = [ gobject-introspection ];
|
||||
|
||||
build-system = [ setuptools ];
|
||||
build-system = with python3Packages; [ setuptools ];
|
||||
|
||||
propagatedBuildInputs = [
|
||||
gdk-pixbuf
|
||||
|
|
@ -40,9 +37,11 @@ buildPythonApplication (finalAttrs: {
|
|||
gtksourceview
|
||||
pango
|
||||
webkitgtk_4_1
|
||||
]
|
||||
++ (with python3Packages; [
|
||||
pygobject3
|
||||
pyyaml
|
||||
];
|
||||
]);
|
||||
|
||||
makeWrapperArgs = [
|
||||
"--set GI_TYPELIB_PATH $GI_TYPELIB_PATH"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ let
|
|||
# keep-sorted start
|
||||
"coc-basedpyright"
|
||||
"coc-clangd"
|
||||
"coc-cmake"
|
||||
"coc-css"
|
||||
"coc-diagnostic"
|
||||
"coc-docker"
|
||||
|
|
|
|||
|
|
@ -4043,20 +4043,6 @@ final: prev: {
|
|||
meta.hydraPlatforms = [ ];
|
||||
};
|
||||
|
||||
coop-nvim = buildVimPlugin {
|
||||
pname = "coop.nvim";
|
||||
version = "0-unstable-2026-04-20";
|
||||
src = fetchFromGitHub {
|
||||
owner = "gregorias";
|
||||
repo = "coop.nvim";
|
||||
rev = "b156e541316aee14be4ae64c93ed8bddb6d03bc1";
|
||||
hash = "sha256-S6iGmdakI714Im0tetgfASbe0K4/olYsjj26+WP+rSU=";
|
||||
};
|
||||
meta.homepage = "https://github.com/gregorias/coop.nvim/";
|
||||
meta.license = getLicenseFromSpdxId "GPL-3.0-only";
|
||||
meta.hydraPlatforms = [ ];
|
||||
};
|
||||
|
||||
copilot-cmp = buildVimPlugin {
|
||||
pname = "copilot-cmp";
|
||||
version = "0-unstable-2024-12-11";
|
||||
|
|
@ -7085,6 +7071,20 @@ final: prev: {
|
|||
meta.hydraPlatforms = [ ];
|
||||
};
|
||||
|
||||
guh-nvim = buildVimPlugin {
|
||||
pname = "guh.nvim";
|
||||
version = "2026-06-09";
|
||||
src = fetchFromGitHub {
|
||||
owner = "justinmk";
|
||||
repo = "guh.nvim";
|
||||
rev = "e8d8df780eb13da78a992fdc387bbc5f1401dd6f";
|
||||
hash = "sha256-vkBP9TvNbUsChtntdgFkHaT01R84HfUAjGXk+SbZUng=";
|
||||
};
|
||||
meta.homepage = "https://github.com/justinmk/guh.nvim/";
|
||||
meta.license = getLicenseFromSpdxId "MIT";
|
||||
meta.hydraPlatforms = [ ];
|
||||
};
|
||||
|
||||
guihua-lua = buildVimPlugin {
|
||||
pname = "guihua.lua";
|
||||
version = "0.1-unstable-2026-05-26";
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ run_require_checks() {
|
|||
if [ "$skip" = false ]; then
|
||||
echo "Attempting to require module: $name"
|
||||
if @nvimBinary@ -es --headless -n -u NONE -i NONE --clean -V1 \
|
||||
--cmd "set rtp+=$out,${deps// /,}" \
|
||||
--cmd "set rtp+=$out,${nativeCheckInputs// /,}" \
|
||||
--cmd "set rtp+=$out,${checkInputs// /,}" \
|
||||
--cmd "set rtp+=${deps// /,}" \
|
||||
--cmd "set rtp+=${nativeCheckInputs// /,}" \
|
||||
--cmd "set rtp+=${checkInputs// /,}" \
|
||||
"${luaPathArgs[@]}" \
|
||||
--cmd "set packpath^=$packPathDir" \
|
||||
--cmd "packadd testPlugin" \
|
||||
|
|
|
|||
|
|
@ -4154,6 +4154,8 @@ assertNoAdditions {
|
|||
};
|
||||
|
||||
nvimSkipModules = [
|
||||
# Example seeds and edits a database during require.
|
||||
"sqlite.examples.bookmarks"
|
||||
# Require "sql.utils" ?
|
||||
"sqlite.tbl.cache"
|
||||
];
|
||||
|
|
|
|||
|
|
@ -287,7 +287,6 @@ https://github.com/niklasdewally/conjure.nvim/,,
|
|||
https://github.com/wellle/context.vim/,,
|
||||
https://github.com/Shougo/context_filetype.vim/,,
|
||||
https://github.com/banjo/contextfiles.nvim/,,
|
||||
https://github.com/gregorias/coop.nvim/,,
|
||||
https://github.com/zbirenbaum/copilot-cmp/,,
|
||||
https://github.com/copilotlsp-nvim/copilot-lsp/,,
|
||||
https://github.com/AndreM222/copilot-lualine/,,
|
||||
|
|
@ -504,6 +503,7 @@ https://github.com/ellisonleao/gruvbox.nvim/,,
|
|||
https://github.com/nvimdev/guard-collection/,,
|
||||
https://github.com/nvimdev/guard.nvim/,,
|
||||
https://github.com/nmac427/guess-indent.nvim/,,
|
||||
https://github.com/justinmk/guh.nvim/,main,
|
||||
https://github.com/ray-x/guihua.lua/,,
|
||||
https://github.com/sjl/gundo.vim/,,
|
||||
https://github.com/junegunn/gv.vim/,,
|
||||
|
|
|
|||
|
|
@ -21,26 +21,26 @@ vscode-utils.buildVscodeMarketplaceExtension (finalAttrs: {
|
|||
sources = {
|
||||
"x86_64-linux" = {
|
||||
arch = "linux-x64";
|
||||
hash = "sha256-q5j8Ip/ew3oHGIakJm/CTeKcW4O9FR062f4rILXbQrQ=";
|
||||
hash = "sha256-R3ab2IeY9QnDhZFk52/05pIv4A+sZU3kJ9Jn5uLRa4Y=";
|
||||
};
|
||||
"aarch64-linux" = {
|
||||
arch = "linux-arm64";
|
||||
hash = "sha256-viZxHDA8SfsIVB5R9I/8SB8EEWRvt1kpZPDA4w0sD54=";
|
||||
hash = "sha256-AE6zS8bJ4vec+P36NkxWYQ1tmcJG2WsFkv75+gRlrxA=";
|
||||
};
|
||||
"x86_64-darwin" = {
|
||||
arch = "darwin-x64";
|
||||
hash = "sha256-kL0bab7BT45EEh17jKFVHqaMQEYkxLlsDKtK1deoS4M=";
|
||||
hash = "sha256-n1qV1Lrl65HSDthMc5/7hLppeNBO6067Z+Rf5+kxfnA=";
|
||||
};
|
||||
"aarch64-darwin" = {
|
||||
arch = "darwin-arm64";
|
||||
hash = "sha256-fJW6fTGRWLBWB1yZ1pGb3p4KkFLhrDXqw+0wjOv71Vo=";
|
||||
hash = "sha256-g+lkUYym43o8cEFseWCrcSUUTx296u8DS9JvnU1dBLU=";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "claude-code";
|
||||
publisher = "anthropic";
|
||||
version = "2.1.161";
|
||||
version = "2.1.172";
|
||||
}
|
||||
// sources.${stdenvNoCC.hostPlatform.system}
|
||||
or (throw "Unsupported system ${stdenvNoCC.hostPlatform.system}");
|
||||
|
|
|
|||
|
|
@ -12,26 +12,26 @@ vscode-utils.buildVscodeMarketplaceExtension {
|
|||
sources = {
|
||||
"x86_64-linux" = {
|
||||
arch = "linux-x64";
|
||||
hash = "sha256-l1bwzuEi8sCBsdad2a5UDPN12QtlHhhgXBfsNxP5GwA=";
|
||||
hash = "sha256-qXGdFXx8Vr9oVStBjaeWEsQjhQUbp9MnLUfJtyhgwkA=";
|
||||
};
|
||||
"x86_64-darwin" = {
|
||||
arch = "darwin-x64";
|
||||
hash = "sha256-31Sj5KlZnRKa0sR2J4A4CRuDF8fwXlzikukH+OX/GpU=";
|
||||
hash = "sha256-Bd3ool5Ep8I5iiTMUHF48r/sf3F1dROx6Umns0pDGzE=";
|
||||
};
|
||||
"aarch64-linux" = {
|
||||
arch = "linux-arm64";
|
||||
hash = "sha256-7m9or/105/YIjhMlwMFLcN9tP9hj/4NU85Y3/5DDuDw=";
|
||||
hash = "sha256-Jv2lrdvY0tthJM2fifUlCW/QBzEZAa8QDHj4o+a4KxY=";
|
||||
};
|
||||
"aarch64-darwin" = {
|
||||
arch = "darwin-arm64";
|
||||
hash = "sha256-q7mGGv/L9N7hwM0EIKF7d+lxcl0V00a6I/CK8j5E8SE=";
|
||||
hash = "sha256-VooAoTyysIFH1AaidcoRs7fJpID0LbmWnLdivGZfdrM=";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "ruff";
|
||||
publisher = "charliermarsh";
|
||||
version = "2026.46.0";
|
||||
version = "2026.48.0";
|
||||
}
|
||||
// sources.${stdenvNoCC.hostPlatform.system}
|
||||
or (throw "Unsupported system ${stdenvNoCC.hostPlatform.system}");
|
||||
|
|
|
|||
|
|
@ -1145,8 +1145,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "vscode-database-client2";
|
||||
publisher = "cweijan";
|
||||
version = "8.4.7";
|
||||
hash = "sha256-HiyLNVtdJgzwn6BSR4ojHOkLrQ49PhRQa4twst69j7Q=";
|
||||
version = "8.5.1";
|
||||
hash = "sha256-adpTh4tNlWFdAGultTLZ9SfN9sMOpMaMWq8x6diGzBg=";
|
||||
};
|
||||
meta = {
|
||||
description = "Database Client For Visual Studio Code";
|
||||
|
|
@ -1215,8 +1215,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "flutter";
|
||||
publisher = "dart-code";
|
||||
version = "3.134.0";
|
||||
hash = "sha256-wWANxBh9Tg3VkfbcrR0NgOIC8cpeZJCNfOevT7E4zKY=";
|
||||
version = "3.136.0";
|
||||
hash = "sha256-RK493qHjEK/k8oy/OIzO3bvNnFo+ZftQhZMIAmBCaJk=";
|
||||
};
|
||||
|
||||
meta.license = lib.licenses.mit;
|
||||
|
|
@ -1375,8 +1375,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "competitive-programming-helper";
|
||||
publisher = "DivyanshuAgrawal";
|
||||
version = "2026.5.1779885478";
|
||||
hash = "sha256-8RU6JWHeYOAxof2TXpeXlXSVD9+0e0E46X85A11l4Pk=";
|
||||
version = "2026.6.1780508121";
|
||||
hash = "sha256-4kb7Nk+gctECMQM/cko+q1Bta1EKPXPEqyCQLBMkbEo=";
|
||||
};
|
||||
meta = {
|
||||
changelog = "https://marketplace.visualstudio.com/items/DivyanshuAgrawal.competitive-programming-helper/changelog";
|
||||
|
|
@ -2052,8 +2052,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "gc-excelviewer";
|
||||
publisher = "grapecity";
|
||||
version = "4.2.65";
|
||||
hash = "sha256-MDGwoecU8km6a7NVQjPRqJ43592Bftd/nXj1cdBB+V8=";
|
||||
version = "4.2.66";
|
||||
hash = "sha256-EFy5GjkgV5puELTzNat+30WC224PLDQJmJeBILc1Fvo=";
|
||||
};
|
||||
meta = {
|
||||
description = "Edit Excel spreadsheets and CSV files in Visual Studio Code and VS Code for the Web";
|
||||
|
|
@ -2324,8 +2324,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "vscode-vibrancy-continued";
|
||||
publisher = "illixion";
|
||||
version = "1.1.77";
|
||||
hash = "sha256-khxajorzIntF2YwKVd6aZ1+doEr2oN4OliBpc7TTB7o=";
|
||||
version = "1.1.78";
|
||||
hash = "sha256-w0i0Gmqj2atCtEYW+0XvZech37qQaTjkt8MJRdHamxs=";
|
||||
};
|
||||
meta = {
|
||||
downloadPage = "https://marketplace.visualstudio.com/items?itemName=illixion.vscode-vibrancy-continued";
|
||||
|
|
@ -3865,8 +3865,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "ansible";
|
||||
publisher = "redhat";
|
||||
version = "26.5.0";
|
||||
hash = "sha256-gKe+LC0OOZi5I1Tei64JtQUR1gpWyTex9MoLGT6jgWU=";
|
||||
version = "26.6.0";
|
||||
hash = "sha256-pCq9niQQIBkiJL6q90W6ecSkGPHttiOAECAyrPgBeqg=";
|
||||
};
|
||||
meta = {
|
||||
description = "Ansible language support";
|
||||
|
|
@ -3997,8 +3997,8 @@ let
|
|||
mktplcRef = {
|
||||
name = "wikitext";
|
||||
publisher = "RoweWilsonFrederiskHolme";
|
||||
version = "4.0.4";
|
||||
hash = "sha256-IEnWoRQfWx4TbysSQlOxG0c8kiqtR4fOhaV1JxDkRCw=";
|
||||
version = "4.0.5";
|
||||
hash = "sha256-VyrcgS93B5Xd4s101lnTw9o27ffcvmxkShCKJ+6H+2w=";
|
||||
};
|
||||
meta = {
|
||||
description = "Extension that helps users view and write MediaWiki's Wikitext files";
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ vscode-utils.buildVscodeMarketplaceExtension rec {
|
|||
mktplcRef = {
|
||||
name = "oracle-java";
|
||||
publisher = "oracle";
|
||||
version = "25.1.0";
|
||||
hash = "sha256-HjDSlvG6khFJA/3ukjVCrPqbQiAKVhgP6KcCfC/jUrc=";
|
||||
version = "26.0.0";
|
||||
hash = "sha256-SfZMOiSuABXcYVi4CmxUUUIeAUmp6s45jjyy4HXoe24=";
|
||||
};
|
||||
|
||||
meta = {
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@
|
|||
let
|
||||
supported = {
|
||||
x86_64-linux = {
|
||||
hash = "sha256-HECflrFni3eWxMs+BpjWBhU3pqF5jjMIEjkp9ibx784=";
|
||||
hash = "sha256-7uZZuEijg1Aca1h2NrBwFU9iFnfhG17waXxqVlAKzTA=";
|
||||
arch = "linux-x64";
|
||||
};
|
||||
x86_64-darwin = {
|
||||
hash = "sha256-dCkSOClWWq3DGU9psrinI5f5oC69K+AhdHdXwKIQsFw=";
|
||||
hash = "sha256-NPh3Sxf2k/Nj4vt0SGsa5H6QOI1IBaL20g79Pl4/iPg=";
|
||||
arch = "darwin-x64";
|
||||
};
|
||||
aarch64-linux = {
|
||||
hash = "sha256-XNIx2ibOe1/1lo8RkYkAv+oBDYpqnmMcIjpoulbrr+w=";
|
||||
hash = "sha256-tszcouaPUGTH1MpGJfU0RiLvBN7qIhH1vC3XiAmHFK8=";
|
||||
arch = "linux-arm64";
|
||||
};
|
||||
aarch64-darwin = {
|
||||
hash = "sha256-rXVuQN0SDmymQNncFZzyD4H+j6hxp1yoiaNXnbzrlo0=";
|
||||
hash = "sha256-JV9pZqq48q00GM0cg3Wu00qrrkn2fczbHBVqnCM84lI=";
|
||||
arch = "darwin-arm64";
|
||||
};
|
||||
};
|
||||
|
|
@ -34,7 +34,7 @@ vscode-utils.buildVscodeMarketplaceExtension {
|
|||
mktplcRef = base // {
|
||||
name = "tombi";
|
||||
publisher = "tombi-toml";
|
||||
version = "1.1.1";
|
||||
version = "1.1.2";
|
||||
};
|
||||
meta = {
|
||||
description = "TOML Language Server";
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ vscode-utils.buildVscodeMarketplaceExtension {
|
|||
// sources.${stdenvNoCC.hostPlatform.system}
|
||||
or (throw "Unsupported system ${stdenvNoCC.hostPlatform.system}");
|
||||
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [
|
||||
autoPatchelfHook
|
||||
];
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ vscode-utils.buildVscodeMarketplaceExtension {
|
|||
mktplcRef = {
|
||||
name = "wgsl-analyzer";
|
||||
publisher = "wgsl-analyzer";
|
||||
version = "0.11.262";
|
||||
hash = "sha256-a2TVwTmxP9wBt0tMkQcVCyzM0RoihGag56ITd+xjtl8=";
|
||||
version = "0.11.318";
|
||||
hash = "sha256-px6lKME6aapi9L9Owb3zhbEMoKmA9GpBQrHtb8Kg0XI=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
|
|
|||
|
|
@ -35,17 +35,17 @@ let
|
|||
|
||||
hash =
|
||||
{
|
||||
x86_64-linux = "sha256-t26YN3E5XaSJ7gki8nm06hVh4ZvXDEU77M749ZrqfAo=";
|
||||
x86_64-darwin = "sha256-jOnwhiDJmU+EqU30wg1+frqDDxJgfngETx414i2YTIg=";
|
||||
aarch64-linux = "sha256-8sYanI12qDMPgVG7S0QKLEkU0i/SICkJ5wz/OwhP+i4=";
|
||||
aarch64-darwin = "sha256-oXeZZWAvpUn5KItEOR8yX9iQ0Fp6EzXGux0jvYbZqtU=";
|
||||
armv7l-linux = "sha256-16cUu1C389edf0aHxXxTLJwjxmpHxM8mv1YFnPDLgP4=";
|
||||
x86_64-linux = "sha256-L975R3F779LgaFTL4B6ZtImPd1LyXhImnDgCPmO5PI8=";
|
||||
x86_64-darwin = "sha256-Sygw/VkIiyV+iABylgFpTiHs0f5dS6NYPWSm5BNh9tQ=";
|
||||
aarch64-linux = "sha256-jcFC668WKAjlYju33RI6poAKnhm3fL1hO16alUwjwv4=";
|
||||
aarch64-darwin = "sha256-AY6WeDzGEH5zXRosN1H/osxC3e5j0Hs9s2Ys2xe1UxI=";
|
||||
armv7l-linux = "sha256-LqofnnZid/I0lVTyhC7yHD+Fxz4dSBxKJ8n+lp2uucQ=";
|
||||
}
|
||||
.${system} or throwSystem;
|
||||
|
||||
# Please backport all compatible updates to the stable release.
|
||||
# This is important for the extension ecosystem.
|
||||
version = "1.122.1";
|
||||
version = "1.123.0";
|
||||
|
||||
# The update server (update.code.visualstudio.com) expects the version path
|
||||
# segment in X.Y.Z form, so we normalize X.Y to X.Y.0 (e.g. "1.110" → "1.110.0").
|
||||
|
|
@ -53,7 +53,7 @@ let
|
|||
downloadVersion = lib.versions.pad 3 version;
|
||||
|
||||
# This is used for VS Code - Remote SSH test
|
||||
rev = "8761a5560cfd65fdd19ce7e2bd18dab5c0a4d84e";
|
||||
rev = "6a44c352bd24569c417e530095901b649960f9f8";
|
||||
in
|
||||
buildVscode {
|
||||
pname = "vscode" + lib.optionalString isInsiders "-insiders";
|
||||
|
|
@ -86,7 +86,7 @@ buildVscode {
|
|||
src = fetchurl {
|
||||
name = "vscode-server-${rev}.tar.gz";
|
||||
url = "https://update.code.visualstudio.com/commit:${rev}/server-linux-x64/stable";
|
||||
hash = "sha256-7n8KvIYEDYO8qqJjfbuUsgUwCxq9FJ6i/EuDBd1HQDk=";
|
||||
hash = "sha256-i034bIsaPlxlVFNY5cKf/ftWPy17SFokbFUMa+zeLng=";
|
||||
};
|
||||
stdenv = stdenvNoCC;
|
||||
};
|
||||
|
|
@ -113,6 +113,9 @@ buildVscode {
|
|||
'';
|
||||
homepage = "https://code.visualstudio.com/";
|
||||
downloadPage = "https://code.visualstudio.com/Updates";
|
||||
changelog = "https://code.visualstudio.com/updates/v${
|
||||
lib.replaceString "." "_" (lib.versions.majorMinor version)
|
||||
}";
|
||||
license = lib.licenses.unfree;
|
||||
maintainers = with lib.maintainers; [
|
||||
eadwu
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ buildVscode rec {
|
|||
'';
|
||||
homepage = "https://github.com/VSCodium/vscodium";
|
||||
downloadPage = "https://github.com/VSCodium/vscodium/releases";
|
||||
changelog = "https://github.com/VSCodium/vscodium/releases/tag/${version}";
|
||||
license = lib.licenses.mit;
|
||||
sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
|
||||
maintainers = with lib.maintainers; [
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
{
|
||||
cmake,
|
||||
pkg-config,
|
||||
callPackage,
|
||||
gobject-introspection,
|
||||
wrapGAppsHook3,
|
||||
python3Packages,
|
||||
libxml2,
|
||||
gnuplot,
|
||||
adwaita-icon-theme,
|
||||
gdk-pixbuf,
|
||||
intltool,
|
||||
libmirage,
|
||||
}:
|
||||
python3Packages.buildPythonApplication {
|
||||
|
||||
inherit
|
||||
(callPackage ./common-drv-attrs.nix {
|
||||
version = "3.2.6";
|
||||
pname = "image-analyzer";
|
||||
hash = "sha256-7I8RUgd+k3cEzskJGbziv1f0/eo5QQXn62wGh/Y5ozc=";
|
||||
})
|
||||
pname
|
||||
version
|
||||
src
|
||||
meta
|
||||
;
|
||||
|
||||
buildInputs = [
|
||||
libxml2
|
||||
gnuplot
|
||||
libmirage
|
||||
adwaita-icon-theme
|
||||
gdk-pixbuf
|
||||
];
|
||||
propagatedBuildInputs = with python3Packages; [
|
||||
pygobject3
|
||||
matplotlib
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
wrapGAppsHook3
|
||||
intltool
|
||||
gobject-introspection
|
||||
];
|
||||
|
||||
pyproject = false;
|
||||
dontWrapGApps = true;
|
||||
preFixup = ''
|
||||
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
callPackage,
|
||||
python3Packages,
|
||||
cmake,
|
||||
pkg-config,
|
||||
intltool,
|
||||
wrapGAppsNoGuiHook,
|
||||
gobject-introspection,
|
||||
}:
|
||||
python3Packages.buildPythonApplication {
|
||||
|
||||
inherit
|
||||
(callPackage ./common-drv-attrs.nix {
|
||||
version = "3.2.5";
|
||||
pname = "cdemu-client";
|
||||
hash = "sha256-py2F61v8vO0BCM18GCflAiD48deZjbMM6wqoCDZsOd8=";
|
||||
})
|
||||
pname
|
||||
version
|
||||
src
|
||||
meta
|
||||
;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
intltool
|
||||
wrapGAppsNoGuiHook
|
||||
gobject-introspection
|
||||
];
|
||||
propagatedBuildInputs = with python3Packages; [
|
||||
dbus-python
|
||||
pygobject3
|
||||
];
|
||||
|
||||
pyproject = false;
|
||||
dontWrapGApps = true;
|
||||
preFixup = ''
|
||||
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
fetchurl,
|
||||
pname,
|
||||
version,
|
||||
hash,
|
||||
}:
|
||||
|
||||
{
|
||||
inherit pname version;
|
||||
src = fetchurl {
|
||||
url = "mirror://sourceforge/cdemu/${pname}-${version}.tar.xz";
|
||||
inherit hash;
|
||||
};
|
||||
meta = {
|
||||
description = "Suite of tools for emulating optical drives and discs";
|
||||
longDescription = ''
|
||||
CDEmu consists of:
|
||||
|
||||
- a kernel module implementing a virtual drive-controller
|
||||
- libmirage which is a software library for interpreting optical disc images
|
||||
- a daemon which emulates the functionality of an optical drive+disc
|
||||
- textmode and GTK clients for controlling the emulator
|
||||
- an image analyzer to view the structure of image files
|
||||
|
||||
Optical media emulated by CDemu can be mounted within Linux. Automounting is also allowed.
|
||||
'';
|
||||
homepage = "https://cdemu.sourceforge.io/";
|
||||
license = lib.licenses.gpl2Plus;
|
||||
platforms = lib.platforms.linux;
|
||||
maintainers = with lib.maintainers; [ bendlas ];
|
||||
};
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
stdenv,
|
||||
callPackage,
|
||||
cmake,
|
||||
pkg-config,
|
||||
glib,
|
||||
libao,
|
||||
intltool,
|
||||
libmirage,
|
||||
coreutils,
|
||||
}:
|
||||
|
||||
let
|
||||
inherit
|
||||
(callPackage ./common-drv-attrs.nix {
|
||||
version = "3.2.7";
|
||||
pname = "cdemu-daemon";
|
||||
hash = "sha256-EKh2G6RA9Yq46BpTAqN2s6TpLJb8gwDuEpGiwdGcelc=";
|
||||
})
|
||||
pname
|
||||
version
|
||||
src
|
||||
meta
|
||||
;
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
inherit pname version src;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
intltool
|
||||
];
|
||||
buildInputs = [
|
||||
glib
|
||||
libao
|
||||
libmirage
|
||||
];
|
||||
postInstall = ''
|
||||
mkdir -p $out/share/dbus-1/services
|
||||
cp -R ../service-example $out/share/cdemu
|
||||
substitute \
|
||||
$out/share/cdemu/net.sf.cdemu.CDEmuDaemon.service \
|
||||
$out/share/dbus-1/services/net.sf.cdemu.CDEmuDaemon.service \
|
||||
--replace /bin/true ${coreutils}/bin/true
|
||||
'';
|
||||
|
||||
meta = {
|
||||
inherit (meta)
|
||||
description
|
||||
license
|
||||
longDescription
|
||||
maintainers
|
||||
platforms
|
||||
;
|
||||
homepage = "https://cdemu.sourceforge.io/about/daemon/";
|
||||
mainProgram = "cdemu-daemon";
|
||||
};
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
{
|
||||
callPackage,
|
||||
cmake,
|
||||
pkg-config,
|
||||
wrapGAppsHook3,
|
||||
gobject-introspection,
|
||||
python3Packages,
|
||||
libnotify,
|
||||
intltool,
|
||||
adwaita-icon-theme,
|
||||
gdk-pixbuf,
|
||||
libappindicator-gtk3,
|
||||
}:
|
||||
python3Packages.buildPythonApplication {
|
||||
|
||||
inherit
|
||||
(callPackage ./common-drv-attrs.nix {
|
||||
version = "3.2.6";
|
||||
pname = "gcdemu";
|
||||
hash = "sha256-w4vzKoSotL5Cjfr4Cu4YhNSWXJqS+n/vySrwvbhR1zA=";
|
||||
})
|
||||
pname
|
||||
version
|
||||
src
|
||||
meta
|
||||
;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
wrapGAppsHook3
|
||||
intltool
|
||||
gobject-introspection
|
||||
];
|
||||
buildInputs = [
|
||||
libnotify
|
||||
adwaita-icon-theme
|
||||
gdk-pixbuf
|
||||
libappindicator-gtk3
|
||||
];
|
||||
propagatedBuildInputs = with python3Packages; [ pygobject3 ];
|
||||
|
||||
pyproject = false;
|
||||
dontWrapGApps = true;
|
||||
preFixup = ''
|
||||
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
||||
'';
|
||||
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
{
|
||||
stdenv,
|
||||
callPackage,
|
||||
cmake,
|
||||
pkg-config,
|
||||
gobject-introspection,
|
||||
vala,
|
||||
glib,
|
||||
libsndfile,
|
||||
zlib,
|
||||
bzip2,
|
||||
xz,
|
||||
libsamplerate,
|
||||
intltool,
|
||||
pcre,
|
||||
util-linux,
|
||||
libselinux,
|
||||
libsepol,
|
||||
}:
|
||||
|
||||
let
|
||||
inherit
|
||||
(callPackage ./common-drv-attrs.nix {
|
||||
version = "3.2.10";
|
||||
pname = "libmirage";
|
||||
hash = "sha256-+T5Gu3VcprCkSJcq/kTySRnNI7nc+GbRtctLkzPhgK4=";
|
||||
})
|
||||
pname
|
||||
version
|
||||
src
|
||||
meta
|
||||
;
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
inherit pname version src;
|
||||
|
||||
env = {
|
||||
PKG_CONFIG_GOBJECT_INTROSPECTION_1_0_GIRDIR = "${placeholder "out"}/share/gir-1.0";
|
||||
PKG_CONFIG_GOBJECT_INTROSPECTION_1_0_TYPELIBDIR = "${placeholder "out"}/lib/girepository-1.0";
|
||||
};
|
||||
|
||||
buildInputs = [
|
||||
glib
|
||||
libsndfile
|
||||
zlib
|
||||
bzip2
|
||||
xz
|
||||
libsamplerate
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
intltool
|
||||
gobject-introspection
|
||||
vala
|
||||
];
|
||||
propagatedBuildInputs = [
|
||||
pcre
|
||||
util-linux
|
||||
libselinux
|
||||
libsepol
|
||||
];
|
||||
|
||||
meta = {
|
||||
inherit (meta)
|
||||
maintainers
|
||||
license
|
||||
platforms
|
||||
;
|
||||
description = "CD-ROM image access library";
|
||||
homepage = "https://cdemu.sourceforge.io/about/libmirage/";
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue