Compare commits

..

434 Commits

Author SHA1 Message Date
nixpkgs-ci[bot]
a01c66acaf Merge 3a43353dd5 into haskell-updates 2026-09-12 00:29:23 +00:00
nixpkgs-ci[bot]
875a3a5dbe Merge 4170b86f20 into haskell-updates 2026-09-10 00:29:12 +00:00
nixpkgs-ci[bot]
40b76b77e7 Merge 4f8e723c59 into haskell-updates 2026-09-09 00:31:23 +00:00
nixpkgs-ci[bot]
dcbf4fd862 Merge cd4578ac64 into haskell-updates 2026-09-08 00:31:09 +00:00
nixpkgs-ci[bot]
af25c7891d Merge 8f5113b1bd into haskell-updates 2026-09-07 00:33:28 +00:00
Wolfgang Walther
ecc90485e0 postgrest: 14.16 -> 16.2 (#560240) 2026-09-06 18:31:51 +00:00
Lukas Epple
582a47d164 haskell.packages.ghc914.haskell-language-server: fix build (#560211) 2026-09-06 15:33:06 +00:00
Wolfgang Walther
35bbabcc81 haskell.packages.ghc914.haskell-language-server: fix build
Fixes the build for HLS on GHC 9.14 without support for hlint or
stylish-haskell, because these two don't support ghc-lib-parser 9.14.x,
yet.
2026-09-06 12:02:47 +02:00
Wolfgang Walther
02f183acd1 haskellPackages: unbreak packages
Generated with maintainers/scripts/haskell/unbreak.nu
2026-09-06 10:19:15 +02:00
Wolfgang Walther
3fb2ae8756 maintainers/scripts/haskell/unbreak: fix
Broken with a nushell update at some point.
2026-09-06 10:14:39 +02:00
Wolfgang Walther
c022230402 haskellPackages: regenerate packages
Generated with
maintainers/scripts/haskell/regenerate-hackage-packages.sh
2026-09-06 10:14:38 +02:00
nixpkgs-ci[bot]
0d161d6bf7 Merge f5f41d5cdf into haskell-updates 2026-09-06 00:33:50 +00:00
Wolfgang Walther
401a7b2ea1 postgrest: 14.16 -> 16.2
Release Notes:
- https://github.com/PostgREST/postgrest/releases/tag/v16.0
- https://github.com/PostgREST/postgrest/releases/tag/v16.1
- https://github.com/PostgREST/postgrest/releases/tag/v16.2
2026-09-05 23:17:42 +02:00
Wolfgang Walther
24d928ae66 haskellPackages.lzma-conduit: pick upstream patch to fix flaky failures (#560187) 2026-09-05 20:31:50 +00:00
Wolfgang Walther
6e8192fc92 haskellPackages: various cleanups in main.yaml (#560252) 2026-09-05 20:31:44 +00:00
sterni
2e8fa702e3 haskellPackages.lzma-conduit: pick upstream patch to fix flaky failures
Had to manually trim down the patch because filterdiff couldn't manage
filtering out just the changes in tests/…
2026-09-05 22:05:52 +02:00
Wolfgang Walther
b228fd3bc9 haskellPackages.servant-openapi3: jailbreak
Also drop dontCheck override, because tests pass.
2026-09-05 18:48:02 +02:00
Wolfgang Walther
14d9e11267 haskellPackages.store: disable tests 2026-09-05 18:39:13 +02:00
Wolfgang Walther
c745615671 haskellPackages: remove obsolete extra-packages
These are not referenced anymore.
2026-09-05 18:25:51 +02:00
Wolfgang Walther
1c75264348 haskellPackages.futhark: fix build 2026-09-05 18:07:10 +02:00
Wolfgang Walther
ebb10ffb74 haskellPackages.chs-cabal: fix build 2026-09-05 18:03:54 +02:00
Wolfgang Walther
abb4be61e6 haskellPackages.hasql-notifications: remove non-functional pin
It's unclear to me why this doesn't cause any changes in
hackage-packages.nix, but it certainly doesn't have any effect - we have
been building 0.2.5.0 before as well, and just fine.
2026-09-05 18:01:46 +02:00
Wolfgang Walther
4479c174f3 haskellPackages: remove some references to "LTS"
We use Nightly now, but the case still stands.
2026-09-05 18:01:01 +02:00
Wolfgang Walther
f3c6c12566 haskellPackages.mighttpd2: remove obsolete pin
Builds now.
2026-09-05 18:00:28 +02:00
Wolfgang Walther
f3f3cd0559 haskellPackages.x509-ocsp: fix build 2026-09-05 17:58:37 +02:00
Wolfgang Walther
d174047339 haskellPackages.http2-tls: fix build 2026-09-05 17:58:36 +02:00
Wolfgang Walther
257e6594e1 haskell.packages.ghc914.dependent-map: jailbreak 2026-09-05 15:13:34 +02:00
Wolfgang Walther
653400d170 haskell.packages.ghc914.tasty-hspec: jailbreak 2026-09-05 15:13:09 +02:00
Wolfgang Walther
65bb1f6dc7 haskell.packages.ghc914: move overrides to correct sections
We have those headers, so we might as well use them...
2026-09-05 13:52:53 +02:00
Wolfgang Walther
e7bb4f9d44 haskell.packages.ghc914: remove obsolete overrides
These build fine without overrides by now.
2026-09-05 13:50:36 +02:00
Wolfgang Walther
8b35ab5a46 haskellPackages: remove obsolete haskellLib. prefixes
There is a `with haskellLib` at the top everywhere.
2026-09-05 13:26:51 +02:00
Wolfgang Walther
b91a28c831 haskellPackages.puresat: update jailbreak 2026-09-05 13:13:04 +02:00
Wolfgang Walther
135ddd3065 haskell.packages.ghc912.patat: drop obsolete jailbreak
This seems to have been fixed. The build still fails, apparently due to
a pandoc update, but not due to a bound on time.
2026-09-05 13:13:03 +02:00
Wolfgang Walther
dfe7bd1c25 haskell.packages.ghc912: remove obsolete overrides specific to GHC 9.12
These all build fine without overrides now.
2026-09-05 13:13:02 +02:00
Wolfgang Walther
af7c2eea09 haskell.packages.ghc912.interpolate: drop obsolete override
GHC 9.12.1 and 9.12.2 have been dropped from Nixpkgs already, so this
won't ever take effect.
2026-09-05 13:13:02 +02:00
Wolfgang Walther
8c4ee9bc8c haskellPackages.pandoc: update test fixtures for djot-0.1.4.2 (#559974) 2026-09-05 11:05:12 +00:00
sterni
a9a8567628 haskellPackages.pandoc: update test fixtures for djot-0.1.4.2 2026-09-05 12:55:41 +02:00
Wolfgang Walther
e021218908 haskellPackages.haskell-language-server: build with cabal-install 3.14 (#546105) 2026-09-05 10:54:19 +00:00
Wolfgang Walther
8175001f58 haskellPackages.cabal-install-parsers: jailbreak in -common.nix 2026-09-05 12:31:21 +02:00
Wolfgang Walther
d6d0eb9bcd haskell.packages.{ghc96,ghc98}.haskell-language-server: fix build 2026-09-05 12:25:42 +02:00
Wolfgang Walther
4111be5b73 haskell.packages.ghc910.haskell-language-server: fix build 2026-09-05 12:25:41 +02:00
Wolfgang Walther
37ecebb9e4 haskell.packages.ghc910.cabal-add: disable test-suite 2026-09-05 12:25:40 +02:00
Wolfgang Walther
8597ae6ab7 haskell.packages.ghc94.haskell-language-server: remove left-over deps 2026-09-05 11:47:37 +02:00
Wolfgang Walther
8bf9cb3ab6 haskellPackages.haskell-language-server: remove outdated extensions override
Recent enough version is shipped by default now.
2026-09-05 11:47:36 +02:00
Alexandre Esteves
1027cca0b0 haskellPackages.haskell-language-server: build with cabal-install 3.14
cabal-add moved from cabal-install-solver to cabal-install itself in
0.2.1:
https://github.com/Bodigrim/cabal-add/blob/master/CHANGELOG.md#021
2026-09-05 11:24:22 +02:00
nixpkgs-ci[bot]
e665ed3e2d Merge 62f65fcdbd into haskell-updates 2026-09-05 00:29:35 +00:00
Wolfgang Walther
2d1fe98d85 haskell.packages.ghc910.haskell-language-server: run treefmt 2026-09-04 21:14:05 +02:00
Wolfgang Walther
41d990226a haskell.packages.ghc910.haskell-language-server: fix eval
apply-refact is marked broken for GHC 9.10. Previously, we did not add
the respective dependencies for this version. Now hackage-packages is
created with GHC 9.12 in mind, so they are added by default - and we
need to remove them for the bad version instead.
2026-09-04 20:29:36 +02:00
Wolfgang Walther
a007df4e16 haskellPackages.haskell-language-server: remove outdated comments 2026-09-04 20:23:57 +02:00
Wolfgang Walther
2b2a0aac02 haskell.packages.ghc914.ormolu: fix eval 2026-09-04 18:29:08 +02:00
nixpkgs-ci[bot]
7554ac32f6 Merge 4238030c5f into haskell-updates 2026-09-04 00:28:52 +00:00
Wolfgang Walther
854435d497 haskellPackages.extensions: default to GHC 9.12 compatible version (#559485) 2026-09-03 18:52:04 +00:00
sterni
667abdf0a6 haskellPackages.extensions: default to GHC 9.12 compatible version 2026-09-03 12:07:56 +02:00
Wolfgang Walther
5cbd2e121e haskellPackages: various fixes around Cabal 3.18 (#553005) 2026-09-03 09:49:38 +00:00
sterni
2bfd7ae693 haskellPackages.entropy: apply compat patch for Cabal 3.18
Note that this patch hasn't been merged/reviewed by upstream yet.
2026-09-03 11:38:20 +02:00
sterni
c7c781f9ad haskellPackages.cabal2nix-unstable: build against jailbroken hpack
Upstream hpack does not allow Cabal 3.18 yet, but builds without
modifications (see linked issue).
2026-09-03 11:37:39 +02:00
Wolfgang Walther
3ad3df3213 haskellPackages.enummapset: move override to configuration-common
The patch only comments out outdated test code, so applies for all GHC
versions.
2026-09-03 10:01:48 +02:00
nixpkgs-ci[bot]
76ae1ad467 Merge aef93b9d19 into haskell-updates 2026-09-03 00:31:46 +00:00
sterni
72169cece3 cabal-install: update overrides for version 3.18.*
Since 3.18 includes the relevant semaphore related patches, we can drop
a lot of extra logic.
2026-09-02 18:17:45 +02:00
sterni
cfda1c7ca7 haskellPackages.Cabal-hooks: build against Cabal == 3.18.* 2026-09-02 18:17:45 +02:00
sterni
f6a92561fc haskellPackages.Cabal_3_18_1_0: wire up with matching Cabal-syntax 2026-09-02 18:17:45 +02:00
sterni
9745c05cf8 haskellPackages.ghc-paths: allow compiling against Cabal 3.18
This is needed e.g. in the cabal-install overlay.
2026-09-02 18:17:45 +02:00
sterni
c94f146ea5 haskellPackages: stackage Nightly 2026-08-27 -> Nightly 2026-09-01
all-cabal-hashes: 2026-08-30T09:16:12Z -> 2026-09-02T14:06:22Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-09-02 18:10:58 +02:00
nixpkgs-ci[bot]
6c41d523f9 Merge 820d011531 into haskell-updates 2026-09-02 00:58:11 +00:00
nixpkgs-ci[bot]
944495f675 Merge 88ad3228bd into haskell-updates 2026-09-02 00:30:55 +00:00
Wolfgang Walther
3314fcd1d2 haskell.packages.ghc914.enummapset: fix tests with containers 0.8, adopt (#557565) 2026-09-01 07:15:02 +00:00
nixpkgs-ci[bot]
d78e1df3ac Merge f7488fa2ba into haskell-updates 2026-09-01 01:58:27 +00:00
Michael Daniels
0c42aa2b8b Merge commit '5e95c5b8ab022bcaa666866aabcf765f22df5c05' into haskell-updates 2026-08-31 21:48:35 -04:00
nixpkgs-ci[bot]
b9f877b238 Merge 810b033819 into haskell-updates 2026-08-31 00:34:10 +00:00
İlkecan Bozdoğan
11e0f4c678 haskellPackages.enummapset: add ilkecan to maintainers 2026-08-30 23:32:04 +03:00
İlkecan Bozdoğan
179eff5553 haskell.packages.ghc914.enummapset: fix tests with containers 0.8 2026-08-30 23:24:15 +03:00
Wolfgang Walther
e7f659cb57 haskellPackages.cabal2nix-unstable: 2.3.0-unstable-2026-06-23 -> 2.3.0-unstable-2026-08-21
Supports Cabal 3.18
2026-08-30 21:58:50 +02:00
Wolfgang Walther
edee302be2 haskellPackages.secp256k1-haskell: drop obsolete patch 2026-08-30 21:51:17 +02:00
Wolfgang Walther
677378b435 haskellPackages.dhall: drop obsolete patches 2026-08-30 21:45:22 +02:00
Wolfgang Walther
51f3af4a42 haskellPackages.yesod-static: patch to use ram over memory (#552197) 2026-08-30 19:31:03 +00:00
Wolfgang Walther
de6e972b4f haskellPackages.*: drop some inactive maintainers (#553837) 2026-08-30 14:20:48 +00:00
Wolfgang Walther
375f55b9dc haskellPackages: stackage Nightly 2026-08-08 -> Nightly 2026-08-27
all-cabal-hashes: 2026-08-09T03:01:25Z -> 2026-08-30T09:16:12Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-08-30 13:26:40 +02:00
nixpkgs-ci[bot]
b21c1bfba8 Merge 91bd06fd96 into haskell-updates 2026-08-30 00:33:36 +00:00
nixpkgs-ci[bot]
64cad13777 Merge b0aa699cd5 into haskell-updates 2026-08-29 00:28:06 +00:00
nixpkgs-ci[bot]
cea0d6d290 Merge d480fadb12 into haskell-updates 2026-08-27 01:35:58 +00:00
Wolfgang Walther
cbc29ba88a haskellPackages.hasktorch: jailbreak (#554074) 2026-08-26 19:34:38 +00:00
nixpkgs-ci[bot]
329a84bda4 Merge bb525e0730 into haskell-updates 2026-08-26 00:15:42 +00:00
Allen Du
039e7d4321 haskellPackages.ghc-typelits-extra: disable testing
tasty tests self-reference built typelits-extra package as a GHC module,
which doesn't work in Nix
2026-08-24 21:51:34 -04:00
Allen Du
895aa19bba haskellPackages.hasktorch: jailbreak
loosen bounds on doctest 0.25 -> 0.26. upstream changes merged
2026-08-24 21:35:23 -04:00
nixpkgs-ci[bot]
0e4dda44be Merge 2c6f56d024 into haskell-updates 2026-08-25 00:15:10 +00:00
nixpkgs-ci[bot]
3ba16f9b5e Merge 8150a74297 into haskell-updates 2026-08-24 00:14:53 +00:00
nixpkgs-ci[bot]
3df67b93de Merge f58bbc7ea2 into haskell-updates 2026-08-23 00:15:20 +00:00
nixpkgs-ci[bot]
8ed8d7cd2f Merge 2f3aa44ed8 into haskell-updates 2026-08-22 00:14:57 +00:00
nixpkgs-ci[bot]
2f153b164f Merge 748cffd26b into haskell-updates 2026-08-21 00:16:00 +00:00
nixpkgs-ci[bot]
f4290a712d Merge 2f6692f65c into haskell-updates 2026-08-20 00:14:50 +00:00
Wolfgang Walther
8125c8f952 haskellPackages: regenerate hackage-packages.nix 2026-08-19 08:57:05 +02:00
Wolfgang Walther
8fb5f5f8a0 haskellPackages: regenerate hackage-packages.nix after maintainer removal 2026-08-19 08:47:09 +02:00
Wolfgang Walther
fc0af5e28b haskellPackages.*: drop peti as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:10 +02:00
Wolfgang Walther
a9d59c8d18 haskellPackages.*: drop ivanbrennan as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:10 +02:00
Wolfgang Walther
13e05d0bc2 haskellPackages.*: drop dschrempf from some of their packages 2026-08-19 08:45:09 +02:00
Wolfgang Walther
8f7c86887d haskellPackages.*: drop Anton-Latukha as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:08 +02:00
Wolfgang Walther
b29c6b8f9c tamarin-prover: drop thoughtpolice as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:07 +02:00
Wolfgang Walther
55bbb3b7c9 haskellPackages.*: drop cdepillabout as maintainer from most packages
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:06 +02:00
Wolfgang Walther
b04bb80014 haskellPackages.*: drop poscat as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:06 +02:00
Wolfgang Walther
93cb8fb139 haskellPackages.*: drop dalpd as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:04 +02:00
Wolfgang Walther
0100807fdc haskellPackages.*: drop Gabriella439 as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:04 +02:00
Wolfgang Walther
89e7632843 haskellPackages.*: drop arturcygan as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:03 +02:00
Wolfgang Walther
2c5eb85631 haskellPackages.*: drop nomeata as maintainer
No reaction to pings in haskell related PRs for a long time.
2026-08-19 08:45:02 +02:00
nixpkgs-ci[bot]
6d4cf664be Merge e44a052fd9 into haskell-updates 2026-08-19 00:14:33 +00:00
Wolfgang Walther
8b057c40b5 haskell.packages.ghc914: misc fixes in preparation for HLS (#553336) 2026-08-18 07:53:04 +00:00
sterni
754e7391d2 haskell.packages.ghc914.generic-lens: disable doctests
It's not clear to me whether it is concerning that this test suite
fails.
2026-08-18 09:43:56 +02:00
sterni
1f46410e29 haskell.packages.ghc914.hie-compat: allow base >= 4.22 2026-08-18 09:43:56 +02:00
sterni
ffd5c0f686 haskell.packages.ghc914.ghc-trace-events: allow base >= 4.22 2026-08-18 09:43:51 +02:00
Wolfgang Walther
b3d151a51a haskellPackages.postgres-websockets: remove obsolete override 2026-08-18 09:22:16 +02:00
nixpkgs-ci[bot]
2f89f5073d Merge 991eb3e013 into haskell-updates 2026-08-18 00:14:48 +00:00
nixpkgs-ci[bot]
c4be39b04d Merge 8d2097f66c into haskell-updates 2026-08-17 00:14:27 +00:00
sterni
c3f4056d8d haskell.packages.ghc914.*rmolu: pick compatible versions 2026-08-16 16:17:06 +02:00
sterni
b455c9d332 haskell.packages.ghc914: move haskell-debugger overrides
Accidentally were in the jailbreaks section.
2026-08-16 16:17:06 +02:00
nixpkgs-ci[bot]
e1647a36da Merge 8c0d357b9f into haskell-updates 2026-08-16 00:15:12 +00:00
sterni
3f450dd19b haskellPackages.yesod-static: patch to use ram over memory
Otherwise, the package will not work together with crypton >= 1.1.
Since we know our version of crypton and, that memory will not be used,
we end up with a very simple patch.
2026-08-15 17:10:55 +02:00
Lukas Epple
841b8f5979 haskell.packages.ghc914: test more packages (#552232) 2026-08-15 12:22:36 +00:00
nixpkgs-ci[bot]
4cd1cda986 Merge 1055f58374 into haskell-updates 2026-08-15 00:14:42 +00:00
Wolfgang Walther
ad3c53a521 darcs: allow tls >= 2.2, http-client-tls >= 0.4 (#552277) 2026-08-14 08:19:04 +00:00
nixpkgs-ci[bot]
5bf4154b18 Merge d9507283e6 into haskell-updates 2026-08-14 00:26:30 +00:00
sterni
b519de25a3 haskell.compiler.ghcHEAD: 10.1.20260514 -> 10.1.20260810 2026-08-13 23:06:23 +02:00
sterni
eaa79b902b darcs: allow tls >= 2.2, http-client-tls >= 0.4 2026-08-13 14:30:34 +02:00
sterni
79f8691e65 darcs: move fgl dep removal into patch 2026-08-13 14:30:34 +02:00
Lukas Epple
3aa4d2d68f haskellPackages: Fix multiple packages maintained by turion (#549454) 2026-08-13 11:35:04 +00:00
sterni
c3d77c8517 Revert "haskell.packages.ghc914: 9.14.1 -> 9.14.1.20260728"
This partially reverts commit 36a316ea88.

Reason for revert: GHC 9.14.2-rc1 breaks a lot of stuff due to
breaking changes in core libs with few fixes for actual packages
available at the moment. Thanks to release-haskell.nix (which
isn't changed by this revert), we should have good visibility
on the state of regressions either way.
2026-08-13 13:30:48 +02:00
sterni
5d1e564405 top-level/release-haskell.nix: add jobs for GHC-9.14.2-rc1 2026-08-13 13:29:18 +02:00
sterni
e58f85ec8d top-level/release-haskell.nix: test more packages on GHC 9.14.1 2026-08-13 12:48:25 +02:00
sterni
877e5290de top-level/release-haskell.nix: test ghc-exactprint for more versions
Since this package has nontrivial overrides for many versions, it's
probably good to add an explicit job.
2026-08-13 12:48:25 +02:00
sterni
4be3abfe1f haskell.packages.ghc914.ghc-lib*: use ver compatible w/ GHC 9.14.1 2026-08-13 12:48:25 +02:00
sterni
5a6a8cded2 haskell.packages.ghc914.ghc-exactprint: adjust to 1.14.0.0 -> 1.14.1.0 2026-08-13 12:48:24 +02:00
sterni
f25caecf7a cabal-install: update haveSemaphoreCompat200 for GHC 9.14.2-rc1
GHC >= 9.14.2 will distribute semaphore-compat >= 2.0.0.
2026-08-13 12:48:24 +02:00
Manuel Bärenz
dbb43d1da6 haskellPackages.monad-schedule: Remove turion as maintainer, comment as unmaintained 2026-08-13 12:35:56 +02:00
Manuel Bärenz
86b532d04c haskellPackages.essence-of-live-coding-warp: disable test suite
The warp test suite runs an HTTP server that needs the threaded RTS, but is
missing ghc-options: -threaded. Fixed upstream in
https://github.com/turion/essence-of-live-coding/pull/153.

Assisted-by: Claude Code (Claude Opus 4.8)
2026-08-13 12:35:56 +02:00
Manuel Bärenz
08f8496ff9 haskellPackages.rhine: disable test suite
Test suite has a too-strict bound QuickCheck <2.16, but nightly ships 2.16.
Bumped upstream in https://github.com/turion/rhine/pull/449.

Assisted-by: Claude Code (Claude Opus 4.8)
2026-08-13 12:35:56 +02:00
Manuel Bärenz
ab222dd942 haskellPackages.monad-schedule: disable test suite
Test suite has a too-strict bound QuickCheck <2.16, but nightly ships 2.16.
Bumped upstream in https://github.com/turion/rhine/pull/449.

Assisted-by: Claude Code (Claude Opus 4.8)
2026-08-13 12:35:56 +02:00
Manuel Bärenz
bb0a89d397 haskellPackages.automaton: disable test suite
Test suite has a too-strict bound QuickCheck <2.16, but nightly ships 2.16.
Bumped upstream in https://github.com/turion/rhine/pull/449.

Assisted-by: Claude Code (Claude Opus 4.8)
2026-08-13 12:35:56 +02:00
Manuel Bärenz
b6af5b43ea haskellPackages.monad-bayes: disable test suite unconditionally
The exact-match SMC/RMSMC benchmark fixtures break with random >= 1.3
(which nightly ships), because the changed PRNG stream alters the sampled
output. Upstream CI stays green only because it is frozen on a 2021 nixpkgs
pin, so make the existing platform-conditional test skip unconditional.

https://github.com/tweag/monad-bayes/issues/368

Assisted-by: Claude Code (Claude Opus 4.8)
2026-08-13 12:35:56 +02:00
sterni
14328fc8f6 haskell.packages.ghc9141.cabal-install: upgrade Cabal library
We need to enable the cabalInstallOverlay for GHC 9.14.1 now since
cabal-install needs Cabal >= 3.16.1 which will only be bundled with
GHC >= 9.14.2.
2026-08-13 12:17:09 +02:00
nixpkgs-ci[bot]
7ad02aa7c0 Merge 4e2e39de80 into haskell-updates 2026-08-13 00:25:40 +00:00
Lukas Epple
311763be2d haskell.compiler.ghc9142: init at 9.14.1.20260728 [ghc-9.14.2-rc1] (#551805) 2026-08-12 15:36:32 +00:00
sterni
36a316ea88 haskell.packages.ghc914: 9.14.1 -> 9.14.1.20260728
This allows us to more easily verifiy that everything is in order
with the RC. Should probably be reverted before this change reaches
master.
2026-08-12 17:27:32 +02:00
sterni
2a38509e0f haskell.compiler.ghc9142: init at 9.14.1.20260728
https://www.haskell.org/ghc/blog/20260730-ghc-9.14.2-rc1-released.html
2026-08-12 11:29:13 +02:00
nixpkgs-ci[bot]
8707585398 Merge 57966db48d into haskell-updates 2026-08-12 00:25:01 +00:00
nixpkgs-ci[bot]
790c31e061 Merge 6077078555 into haskell-updates 2026-08-11 00:20:45 +00:00
nixpkgs-ci[bot]
1b8e493a4c Merge 5cdd538691 into haskell-updates 2026-08-10 00:21:28 +00:00
Wolfgang Walther
58673d30d4 haskellPackages: stackage Nightly 2026-07-26 -> Nightly 2026-08-08
all-cabal-hashes: 2026-07-26T14:06:58Z -> 2026-08-09T03:01:25Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-08-09 11:24:03 +02:00
nixpkgs-ci[bot]
beccc5847a Merge 92fc51132a into haskell-updates 2026-08-09 00:20:21 +00:00
Michael Daniels
3adf419aa4 Merge commit 'ce3d7ffb9855af1b68e2cac174e2a21c5fbef679' into haskell-updates 2026-08-08 16:33:17 -04:00
nixpkgs-ci[bot]
b52f4adde7 Merge cad39ce77b into haskell-updates 2026-08-04 00:37:07 +00:00
nixpkgs-ci[bot]
bd16497ad4 Merge 243895692a into haskell-updates 2026-08-03 00:38:12 +00:00
Wolfgang Walther
ffc266319e Merge commit '1681e76bd69a4fd0be27552e93b1abdec67392d5' into haskell-updates 2026-08-02 10:53:07 +02:00
Wolfgang Walther
fa192c1915 haskell.packages.ghc948.cabal2nix: fix deps (#545987) 2026-07-28 20:40:39 +00:00
Wolfgang Walther
78d4679404 haskellPackages.cabal-add: update patch (#543503) 2026-07-27 20:07:58 +00:00
Alexandre Esteves
a05b62f756 haskellPackages.cabal-add: update patch 2026-07-27 20:38:02 +01:00
Wolfgang Walther
2e37254a0d haskellPackages.changelog-d: Jailbreak to support latest deps (#546290) 2026-07-27 18:56:39 +00:00
Lukas Epple
e1f0c80964 haskellPackages.cabal-plan-bounds: Jailbreak to support latest deps (#546033) 2026-07-27 11:09:18 +00:00
nixpkgs-ci[bot]
3ae4f100fa Merge d3498f786f into haskell-updates 2026-07-27 00:39:05 +00:00
Wolfgang Walther
b92b966ae0 haskellPackages.bytezap: Jailbreak to support base 4.22 (#546007) 2026-07-26 17:24:09 +00:00
Wolfgang Walther
3f0da4e5f2 haskell.packages.ghc948.cabal2nix: fix deps
base64 only bumped the lower bounds on base in
https://github.com/emilypi/base64/pull/67 via revision, no code changes.
Safe to jailbreak.

crypton-x509-store only depends on unix without a version bound today,
so no need to downgrade.
2026-07-26 19:17:26 +02:00
Wolfgang Walther
338603c0d4 haskellPackages.git-annex: fix hash 2026-07-26 17:19:07 +02:00
Michael Daniels
3c1773c843 Merge commit '116e3485d174e7123a2b98392c79c4ff62c4720b' into haskell-updates 2026-07-26 11:02:41 -04:00
Wolfgang Walther
826465b345 haskellPackages: stackage Nightly 2026-07-24 -> Nightly 2026-07-26
all-cabal-hashes: 2026-07-24T18:50:05Z -> 2026-07-26T14:06:58Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-07-26 16:49:48 +02:00
Wolfgang Walther
ad05226f3d haskellPackages.text-icu: skip flaky t_blockCode test (#545967) 2026-07-26 14:30:45 +00:00
Wolfgang Walther
9da5406197 haskellPackages.amazonka-{core,s3-encryption}: allow crypton 1.1 (#545908) 2026-07-26 14:28:16 +00:00
Wolfgang Walther
21dcddba97 haskellPackages.amazonka-s3-encryption: unbreak 2026-07-26 16:23:23 +02:00
Wolfgang Walther
f8b6781bea haskellPackages.amazonka-{core,s3-encryption}: allow crypton 1.1 2026-07-26 16:23:14 +02:00
Wolfgang Walther
e83add3066 haskellPackages: regenerate hackage-packages.nix 2026-07-26 16:23:11 +02:00
sterni
d4fadf1842 haskellPackages.text-icu: skip flaky t_blockCode test
See https://github.com/haskell/text-icu/issues/103
2026-07-26 16:15:57 +02:00
sterni
48ea35d0b8 haskellPackages.text-icu: apply patch for time rendering test
See https://github.com/haskell/text-icu/issues/108.
2026-07-26 16:13:39 +02:00
Lukas Epple
5903a7f72d haskellPackages.dhall: fix build with http-client-tls 0.4 (#545900) 2026-07-26 14:06:25 +00:00
Wolfgang Walther
a428929e72 haskellPackages.arch-web: Jailbreak to allow latest http-client-tls (#545911) 2026-07-26 13:03:36 +00:00
Akshay Mankar
d6499c4e3c haskellPackages.changelog-d: Jailbreak to support latest deps 2026-07-26 14:55:05 +02:00
Akshay Mankar
9728ac8f06 haskellPackages.cabal-plan-bounds: Jailbreak to support latest deps 2026-07-26 14:34:45 +02:00
Akshay Mankar
1ae532eb77 haskellPackages.bytezap: Jailbreak to support base 4.22 2026-07-26 14:29:32 +02:00
Akshay Mankar
5df69cc621 haskellPackages.arch-web: Jailbreak to allow latest http-client-tls 2026-07-26 14:28:41 +02:00
Wolfgang Walther
6046acb728 haskellPackages.dhall: fix build with http-client-tls 0.4 2026-07-26 12:14:03 +02:00
Wolfgang Walther
87283c7045 haskellPackages.*: move generateOptparseApplicativeCompletions to configuration-nix.nix
Nothing temporary about these.
2026-07-26 12:14:02 +02:00
sterni
ea31f133da haskell.packages.microhs.time: 1.16 -> 1.16.0.1
(To fix evaluation.)
2026-07-25 11:36:16 +02:00
nixpkgs-ci[bot]
5a5cd26432 Merge a016e17772 into haskell-updates 2026-07-25 00:37:35 +00:00
Lukas Epple
d47687c04d [haskell-updates] haskellPackages: stackage Nightly 2026-07-13 -> Nightly 2026-07-24 (#545393) 2026-07-24 21:53:13 +00:00
sterni
08f0950a50 haskell.packages.microhs.haskeline: 0.8.4.1 -> 0.8.5.0
(To fix evaluation.)
2026-07-24 23:35:24 +02:00
sterni
f4c6e009f9 haskellPackages.yesod-test: avoid infinite recursion 2026-07-24 23:28:15 +02:00
sterni
a1beaf2803 haskellPackages.no-recursion: drop obsolete override 2026-07-24 23:25:28 +02:00
sterni
3594aefa35 haskellPackages: stackage Nightly 2026-07-13 -> Nightly 2026-07-24
all-cabal-hashes: 2026-07-15T08:37:28Z -> 2026-07-24T18:50:05Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-07-24 22:05:31 +02:00
Lukas Epple
3b19ff96a1 [haskell-updates] haskell.packages.ghc9125: 9.12.4.20260614 -> 9.12.4.20260713 (#544619) 2026-07-24 20:01:07 +00:00
nixpkgs-ci[bot]
19573606e8 Merge e220185ff6 into haskell-updates 2026-07-24 00:34:22 +00:00
nixpkgs-ci[bot]
7632f2c418 Merge 6e369fe949 into haskell-updates 2026-07-23 00:36:30 +00:00
sterni
b393efc343 haskell.packages.ghc9125: 9.12.4.20260614 -> 9.12.4.20260713
rc2 -> rc3
2026-07-22 19:32:38 +02:00
nixpkgs-ci[bot]
eef2380c20 Merge dde6423243 into haskell-updates 2026-07-22 00:34:47 +00:00
nixpkgs-ci[bot]
e3c24ee8db Merge c91334b372 into haskell-updates 2026-07-21 00:36:50 +00:00
Malte Ott
116208d9cf haskellPackages.hie-bios: restrict to 0.19 (#543505) 2026-07-20 15:54:18 +00:00
nixpkgs-ci[bot]
a332844436 Merge cbf17f2c3c into haskell-updates 2026-07-20 00:39:47 +00:00
Alexandre Esteves
86ed8342de haskellPackages: regenerate package set based on current config 2026-07-19 13:45:57 +01:00
Alexandre Esteves
31f495afe9 haskellPackages.hie-bios: restrict to 0.19 2026-07-19 13:45:49 +01:00
nixpkgs-ci[bot]
da941382a6 Merge 2a83e50fab into haskell-updates 2026-07-19 00:37:23 +00:00
Wolfgang Walther
920b50911d [haskell-updates] haskellPackages: stackage Nightly 2026-06-26 -> Nightly 2026-07-13 (#543047) 2026-07-18 06:01:42 +00:00
Wolfgang Walther
43159787fd haskellPackages.rerefined: allow QuickCheck 2.16 (#536459) 2026-07-18 06:01:28 +00:00
nixpkgs-ci[bot]
a603053a30 Merge b5d95a3fd3 into haskell-updates 2026-07-18 00:34:07 +00:00
Wolfgang Walther
5865c4be2c haskellPackages.postgres-websockets: update jailbreak 2026-07-17 22:39:16 +02:00
Wolfgang Walther
b72ec6bdee haskellPackages.no-recursion: warn for obsolete override
A fix has been merged upstream, but not released, yet - so adding the
warning to pick that up automatically on the next bump.
2026-07-17 22:39:08 +02:00
Wolfgang Walther
c818fb7e53 haskellPackages: drop various obsolete overrides after hackage bump 2026-07-17 22:39:04 +02:00
Wolfgang Walther
88daa4b688 haskellPackages: regenerate hackage-packages.nix 2026-07-17 22:33:28 +02:00
Wolfgang Walther
d82c0d269e haskellPackages.mlkem: disable tests 2026-07-17 22:33:26 +02:00
Wolfgang Walther
0b6b59708c haskellPackages: stackage Nightly 2026-06-26 -> Nightly 2026-07-13
all-cabal-hashes: 2026-06-26T06:10:51Z -> 2026-07-15T08:37:28Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-07-17 22:33:25 +02:00
Wolfgang Walther
9220258efb haskellPackages.mlkem: unmark broken
This package is still effectively broken at this stage, but the next
bump to stackage will add mlkem as a dependency of tls, which is in the
dependency chain of cabal2nix itself.

The same bump will update crypton and thus make mlkem build - but we
can't mark it unbroken, when cabal2nix-unstable fails to run because one
of its dependencies is marked broken...
2026-07-17 22:09:38 +02:00
nixpkgs-ci[bot]
a8560ee995 Merge 3caf6c92ce into haskell-updates 2026-07-17 00:36:58 +00:00
nixpkgs-ci[bot]
cfdc80cdd7 Merge 8288eae5a4 into haskell-updates 2026-07-16 00:35:07 +00:00
Wolfgang Walther
523ffbe971 haskellPackages.rapid: patch bounds (#541874) 2026-07-15 06:41:29 +00:00
nixpkgs-ci[bot]
3aed88a715 Merge 2c726dc782 into haskell-updates 2026-07-15 00:30:56 +00:00
Alexandre Esteves
1c3465fcb7 haskellPackages: regenerate package set based on current config 2026-07-14 17:57:03 +01:00
Alexandre Esteves
54112f9a6b haskellPackages.rapid: patch bounds 2026-07-14 17:56:50 +01:00
nixpkgs-ci[bot]
92cbc9ca81 Merge d95279435c into haskell-updates 2026-07-14 00:33:37 +00:00
nixpkgs-ci[bot]
6a3c990a99 Merge 310b8cc6a5 into haskell-updates 2026-07-13 00:38:09 +00:00
nixpkgs-ci[bot]
39ee207b1d Merge dd93798a29 into haskell-updates 2026-07-12 00:38:11 +00:00
nixpkgs-ci[bot]
d64edb78f9 Merge ffc7f8ce99 into haskell-updates 2026-07-11 00:36:01 +00:00
nixpkgs-ci[bot]
54726cb9e3 Merge 0e6ff04fc5 into haskell-updates 2026-07-10 00:42:12 +00:00
nixpkgs-ci[bot]
b7659cdb62 Merge 8ab1ccd1c1 into haskell-updates 2026-07-09 00:41:01 +00:00
nixpkgs-ci[bot]
bcf85400c4 Merge bd3c09ca2a into haskell-updates 2026-07-08 00:36:49 +00:00
nixpkgs-ci[bot]
e3927c07f7 Merge 60f3895575 into haskell-updates 2026-07-07 00:43:55 +00:00
nixpkgs-ci[bot]
8486e8a7b3 Merge fbdfe58264 into haskell-updates 2026-07-06 00:43:34 +00:00
nixpkgs-ci[bot]
4f0970401a Merge 7d5d19274b into haskell-updates 2026-07-05 00:43:51 +00:00
nixpkgs-ci[bot]
9959ce2f44 Merge f91cfe02f8 into haskell-updates 2026-07-04 00:40:56 +00:00
nixpkgs-ci[bot]
3f085fe61c Merge 9778ed5674 into haskell-updates 2026-07-03 00:42:09 +00:00
Wolfgang Walther
f61423d87c haskellPackages.lambdabot: remove ncfavier as maintainer (#537887) 2026-07-02 19:57:54 +00:00
Naïm Camille Favier
4aeebf57da haskellPackages.lambdabot: remove ncfavier as maintainer 2026-07-02 19:38:32 +02:00
Wolfgang Walther
4c7647a6d3 haskell.packages.ghc{96,98}.haskell-language-server: fix build (#537724) 2026-07-02 10:10:33 +00:00
Wolfgang Walther
afda14f1d4 dhall-lsp-server: fix build with lsp 2.8 2026-07-02 10:31:48 +02:00
Wolfgang Walther
e9af2ed4be haskellPackages.no-recursion: jailbreak 2026-07-02 10:23:39 +02:00
Wolfgang Walther
2735e861f0 haskell.packages.ghc{96,98}.haskell-language-server: fix build
Jailbreaks are due to optparse-applicative.
2026-07-02 10:07:26 +02:00
Wolfgang Walther
92ca07b6a5 haskellPackages.threadscope: jailbreak 2026-07-02 09:48:12 +02:00
Wolfgang Walther
e82d6b924f haskellPackages.taskwarrior: jailbreak 2026-07-02 09:43:24 +02:00
Wolfgang Walther
94aa8f8960 haskellPackages.shh{,-extras}: jailbreak 2026-07-02 09:41:11 +02:00
Wolfgang Walther
75496eb67a haskellPackages.eventlog2html: jailbreak 2026-07-02 09:36:13 +02:00
Wolfgang Walther
9c55dbeccf [haskell-updates] stack: patch for semaphore-compat >= 2.0 (#534567) 2026-07-02 07:25:00 +00:00
Wolfgang Walther
cef090d1ab haskellPackages.optics: pick patches that make test suite pass with 9.12 (#536009) 2026-07-02 07:19:43 +00:00
sterni
4132fb9736 haskellPackages.optics: pick patches that make test suite pass with 9.12
I'm not 100% clear whether there is still some kind of GHC regression
involved here, but I think we can pick these patches from upstream's
development branch. Also GHC upstream is aware of these (original)
failures with 9.12.5-rc2.
2026-07-02 09:13:52 +02:00
Wolfgang Walther
98c655c09a haskellPackages.*: compile a few test suites with threaded runtime (#537144) 2026-07-02 07:06:56 +00:00
nixpkgs-ci[bot]
3f49232af6 Merge 8037b1aab1 into haskell-updates 2026-07-02 00:50:41 +00:00
nixpkgs-ci[bot]
7100632254 Merge 5bb269961b into haskell-updates 2026-07-01 00:56:02 +00:00
Alexandre Esteves
b078be0041 haskellPackages.*: compile a few test suites with threaded runtime 2026-07-01 01:01:33 +01:00
nixpkgs-ci[bot]
92779d4478 Merge 3b1d058d00 into haskell-updates 2026-06-30 00:53:14 +00:00
sterni
070e7a021f haskellPackages.futhark-manifest: use version requested by futhark-0.26.3 2026-06-29 23:56:40 +02:00
Wolfgang Walther
71b5964ed6 haskellPackages.{yaya*}: allow doctest 0.25 (#536739) 2026-06-29 18:04:32 +00:00
Wolfgang Walther
00a35c51c7 haskellPackages.{yaya*}: allow doctest 0.25 2026-06-29 19:55:06 +02:00
Wolfgang Walther
dbd129b241 haskellPackages.graphviz: allow QuickCheck 2.16 (#536737) 2026-06-29 17:54:14 +00:00
Wolfgang Walther
26066e1e2b haskellPackages.graphviz: allow QuickCheck 2.16 2026-06-29 19:28:59 +02:00
nixpkgs-ci[bot]
60f1d07046 Merge 2df5d1313a into haskell-updates 2026-06-29 00:55:22 +00:00
Wolfgang Walther
a5e06de0c4 haskellPackages.servant-{auth-client,auth-docs,auth-server,swagger}: jailbreak (#536456) 2026-06-28 22:21:46 +00:00
Wolfgang Walther
8833922b3e haskellPackages.rerefined: allow QuickCheck 2.16 2026-06-28 23:57:31 +02:00
Wolfgang Walther
d0e8fdd1bd haskellPackages.servant-{auth-client,auth-docs,auth-server,swagger}: jailbreak 2026-06-28 23:39:46 +02:00
sterni
9122c84035 git-annex: delete unused patch file 2026-06-28 16:15:35 +02:00
sterni
f479cbacab stack: apply patches for semaphore-compat >= 2.0
Apply patches from https://github.com/commercialhaskell/stack/pull/6935
allowing us to build stack with GHC 9.12.5-rc2 (but no other GHC version).
Patch for the change log is not included (due to likely conflict problems),
but other documentation included with stack is updated.

We also apply an unrelated bug fix, so we don't need to rebase the patches.
2026-06-28 16:12:15 +02:00
sterni
f87fabdc91 stack: drop released patch 2026-06-28 16:11:51 +02:00
sterni
f94cecf640 haskell.packages.ghc910.stack: remove compat code
Ideally, we won't use this going forward and just build stack with GHC 9.12
2026-06-28 15:45:51 +02:00
Wolfgang Walther
fc0932307c pkgsStatic.haskell.packages.native-bignum.ghc948.postgrest: fix build
Removes a dependency which had long been replaced upstream, but the
expression is still generated from the outdated hackage package.

The GHC 9.4.8 static variant is still used upstream, but we will be able
to remove it from the release set on PostgREST's next release.
2026-06-28 10:47:04 +02:00
Wolfgang Walther
ffbec19b05 haskellPackages.git-annex: update hash 2026-06-28 10:32:42 +02:00
nixpkgs-ci[bot]
435e7264b6 Merge bdd995eaee into haskell-updates 2026-06-28 00:54:07 +00:00
sternenseemann
480f0726e7 [haskell-updates] haskellPackages: stackage Nightly 2026-06-20 -> Nightly 2026-06-26 (#534748) 2026-06-27 11:29:35 +00:00
nixpkgs-ci[bot]
4d0ae93287 Merge 538087c016 into haskell-updates 2026-06-27 00:52:07 +00:00
sternenseemann
81ef0ce73b haskellPackages.wai-app-file-cgi: pin to < 3.2.0 for mighttpd2 (#535246) 2026-06-26 11:13:45 +00:00
sterni
24211dd381 haskellPackages.wai-app-file-cgi: pin to < 3.2.0 for mighttpd2
Requires picking a compat patch from 3.2.1 for http-types-0.12.5.
2026-06-26 13:04:54 +02:00
sterni
8b99224c3e haskellPackages.statistics: drop obsolete override 2026-06-26 10:48:10 +02:00
sterni
d56383f426 haskellPackages: stackage Nightly 2026-06-20 -> Nightly 2026-06-26
all-cabal-hashes: 2026-06-20T12:32:58Z -> 2026-06-26T06:10:51Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-06-26 10:48:10 +02:00
nixpkgs-ci[bot]
2836c4b1f4 Merge 19e056881c into haskell-updates 2026-06-26 00:54:38 +00:00
Wolfgang Walther
16a3b0c7d9 [haskell-updates] git-annex: unbreak (#534543) 2026-06-25 08:31:42 +00:00
Wolfgang Walther
7db16b7a40 top-level/release-haskell.nix: use ghc 9.12 in versioned jobs (#534745) 2026-06-25 07:55:36 +00:00
nixpkgs-ci[bot]
85b5c86354 Merge 19a053f28c into haskell-updates 2026-06-25 00:53:29 +00:00
nixpkgs-ci[bot]
3f6c25ad80 Merge dd4c7b49b6 into haskell-updates 2026-06-24 00:48:36 +00:00
sterni
a8988fede0 top-level/release-haskell.nix: drop ghc9125 exclusions
These packages need to work in the default package set anyways!
2026-06-23 23:36:56 +02:00
sterni
68f69e8b05 top-level/release-haskell.nix: prefer ghc9125 over ghc9123 2026-06-23 23:36:56 +02:00
Robert Hensing
9bbb567bb9 haskellPackages.hercules-ci-optparse-applicative: 0.19.0.0-fork-0 -> 0.19.0.0-fork-1 2026-06-23 17:11:40 +02:00
sterni
5f8a3af9eb haskellPackages.git-annex: patch for http-types >= 0.12.5 2026-06-23 12:55:31 +02:00
sterni
b25e3e8489 git-annex: update sha256 for 10.20260601 2026-06-23 12:55:31 +02:00
sterni
a220c38f46 haskellPackages.cabal2nix-unstable: 2026-03-30 -> 2026-06-23
This makes sure the libmagic dependency of haskellPackages.magic
is resolved correctly again.
2026-06-23 12:55:25 +02:00
sterni
fdbcfd8b47 haskellPackages.statistics: allow doctest >= 0.25 2026-06-23 10:17:49 +02:00
sterni
eff6c0e60e darcs: patch incompatibilities with Stackage Nightly and Cabal 3.14 2026-06-23 10:17:49 +02:00
nixpkgs-ci[bot]
5a03008b47 Merge 691bc285bc into haskell-updates 2026-06-23 00:52:15 +00:00
nixpkgs-ci[bot]
6dd4da168b Merge 6e7f01b46b into haskell-updates 2026-06-22 00:59:28 +00:00
Alexandre Esteves
4cbc2251c7 haskellPackages.haskell-language-server: fix or bump deps (#525752) 2026-06-22 00:38:49 +00:00
Alexandre Esteves
a8233a24e1 haskellPackages: regenerate package set based on current config 2026-06-21 23:04:56 +01:00
Alexandre Esteves
da4f3989f0 haskellPackages.haskell-language-server: add myself as maintainer including deps 2026-06-21 22:44:59 +01:00
Alexandre Esteves
e0497b3d10 haskellPackages: drop obsolete package upgrades 2026-06-21 22:44:07 +01:00
Alexandre Esteves
a49c815e3d haskellPackages: regenerate package set based on current config 2026-06-21 22:43:24 +01:00
Alexandre Esteves
f213d6af36 haskellPackages.haskell-language-server: unrestrict deps 2026-06-21 22:30:23 +01:00
Alexandre Esteves
aba749b3bb haskellPackages.stylish-haskell: patch bound 2026-06-21 22:30:07 +01:00
Wolfgang Walther
e64658550c cabal-install: patch for compatibility with semaphore-compat-2.0.0 (#531658) 2026-06-21 09:11:29 +00:00
Wolfgang Walther
07d2edc929 haskellPackages.gitit: drop obsolete overrides 2026-06-21 10:47:07 +02:00
nixpkgs-ci[bot]
b52ea84a40 Merge dccba7b9f2 into haskell-updates 2026-06-21 00:59:34 +00:00
sterni
f394a62a65 cabal-install: patch for compatibility with semaphore-compat-2.0.0
This is necessary pending a release of cabal-install-3.18 (and Cabal-3.18).
Since the patch for Cabal changes the public API, I've chosen to only
apply it inside the cabal-install overlay for now.
2026-06-21 02:39:54 +02:00
sternenseemann
ad66699b02 [haskell-updates] haskellPackages: stackage Nightly 2026-06-09 -> Nightly 2026-06-16 (#530271) 2026-06-21 00:30:46 +00:00
sterni
084d450fa7 haskell.packages.ghc9125: 9.12.4.20260606 -> 9.12.4.20260614 2026-06-20 19:18:03 +02:00
Wolfgang Walther
ec138222f7 haskellPackages.postgres-websockets: jailbreak (wai-app-static) 2026-06-20 19:18:03 +02:00
sterni
5a13f175d1 haskellPackages.hakyll-filestore: drop obsolete override 2026-06-20 19:18:03 +02:00
Wolfgang Walther
117625921f haskellPackages.hw-prim: drop obsolete jailbreak 2026-06-20 19:18:03 +02:00
Wolfgang Walther
2c44031fe0 haskellPackages.vector: drop obsolete jailbreak 2026-06-20 19:18:03 +02:00
sterni
d34ba4d817 haskellPackages: stackage Nightly 2026-06-09 -> Nightly 2026-06-20
all-cabal-hashes: 2026-06-09T15:28:54Z -> 2026-06-20T12:32:58Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-06-20 19:18:02 +02:00
nixpkgs-ci[bot]
e34ce374a1 Merge 6c91888634 into haskell-updates 2026-06-20 00:54:18 +00:00
nixpkgs-ci[bot]
a00be59a94 Merge f7df78e77a into haskell-updates 2026-06-19 01:03:53 +00:00
nixpkgs-ci[bot]
ab20ff9b2f Merge a0fe7a7f2e into haskell-updates 2026-06-18 00:58:39 +00:00
nixpkgs-ci[bot]
995d34a153 Merge 8cf9f7fff1 into haskell-updates 2026-06-17 00:58:42 +00:00
Wolfgang Walther
9208b19946 haskellPackages.{rvar,QuickCheck-safe}: fix build (#531374) 2026-06-16 20:14:29 +00:00
nixpkgs-ci[bot]
9029909ba3 Merge 5a21d1bfee into haskell-updates 2026-06-16 01:04:21 +00:00
nixpkgs-ci[bot]
b82be3afe6 Merge 635f366cf9 into haskell-updates 2026-06-15 00:59:45 +00:00
Naïm Camille Favier
248b70dc3b haskellPackages.QuickCheck-safe: allow build with QuickCheck 2.16 2026-06-14 16:11:41 +02:00
Naïm Camille Favier
0baca65faa haskellPackages.{rvar,random-fu}: fix build 2026-06-14 16:11:11 +02:00
nixpkgs-ci[bot]
b1528a1baf Merge a18d24ff2b into haskell-updates 2026-06-14 00:57:26 +00:00
Wolfgang Walther
200316c491 haskellPackages/fused-effects: jailbreak because of too tight hedgedoc dep (#531331) 2026-06-13 12:49:06 +00:00
mangoiv
3c4f10205c haskellPackages/fused-effects: jailbreak because of too tight hedgedog dep 2026-06-13 14:03:44 +02:00
Wolfgang Walther
827c840fb1 haskellPackages.validation: pin to 1.1.5 (#530365) 2026-06-13 11:43:41 +00:00
Allen Du
095f6729ca haskellPackages.validation: pin to 1.1.5 2026-06-13 10:17:35 +02:00
Wolfgang Walther
1352e67378 haskellPackages: regenerate hackage-packages.nix 2026-06-13 10:17:11 +02:00
nixpkgs-ci[bot]
0814616eaf Merge 08740d8811 into haskell-updates 2026-06-13 00:57:33 +00:00
nixpkgs-ci[bot]
f70431ea67 Merge 20c18080b0 into haskell-updates 2026-06-12 00:58:47 +00:00
sterni
8383c3f904 haskellPackages.hakyll-filestore: allow hakyll >= 4.17 2026-06-11 22:38:23 +02:00
nixpkgs-ci[bot]
cac8c10692 Merge d9c4084332 into haskell-updates 2026-06-11 00:55:35 +00:00
Wolfgang Walther
739281cf7a haskellPackages.yesod-middleware-csp: jailbreak & unbreak (#529859) 2026-06-10 09:49:07 +00:00
Michael Schneider
ef5a2561e3 haskellPackages.yesod-middleware-csp: 1.2.0 -> 1.3.0 2026-06-10 16:40:50 +07:00
sterni
a5f1afdf0f haskellPackages.pandoc: drop patch applied by upstream 2026-06-10 06:40:59 +02:00
sternenseemann
cbe86ed815 [haskell-updates] haskellPackages: stackage Nightly 2026-05-27 -> Nightly 2026-06-07 (#529097) 2026-06-09 16:33:20 +00:00
Wolfgang Walther
5617c0ba47 haskellPackages: stackage Nightly 2026-05-27 -> Nightly 2026-06-09
all-cabal-hashes: 2026-05-28T09:17:22Z -> 2026-06-09T15:28:54Z

(generated by maintainers/scripts/haskell/update-package-set.sh)

Co-authored-by: sterni <sternenseemann@systemli.org>
2026-06-09 18:08:40 +02:00
sternenseemann
caf8327196 git-annex: build against filepath-bytestring instead of file-io (#527916) 2026-06-09 15:35:27 +00:00
sternenseemann
89b9cdcbba haskellPackages.{bitwise,psqueues,xz}: drop override (#525905) 2026-06-09 15:33:55 +00:00
sternenseemann
3c3354afa3 haskell.packages.ghc912: 9.12.3 -> 9.12.4.20260606 (#529900) 2026-06-09 15:11:44 +00:00
sterni
8cc9c34bcb haskell.packages.ghc9{4,6}.semaphore-compat: 1.0.0 -> 2.0.0
This matches GHC 9.12.5.
2026-06-09 15:49:31 +02:00
sterni
8c3d964e79 haskell.packages.ghc912: 9.12.3 -> 9.12.4.20260606 2026-06-09 13:54:57 +02:00
nixpkgs-ci[bot]
cadaf97e4e Merge 3438114c15 into haskell-updates 2026-06-09 00:50:54 +00:00
nixpkgs-ci[bot]
593c21a56a Merge f77c3e23e5 into haskell-updates 2026-06-08 00:57:17 +00:00
Wolfgang Walther
6306c15610 elmPackages.elm-format: jailbreak (#529072) 2026-06-07 10:03:20 +00:00
Marek Fajkus
884892c2c1 elmPackages.elm-format: jailbreak 2026-06-07 11:40:59 +02:00
nixpkgs-ci[bot]
627dd785ad Merge 38d9adc8ca into haskell-updates 2026-06-07 00:56:22 +00:00
nixpkgs-ci[bot]
180157dfa4 Merge b99e1dabec into haskell-updates 2026-06-06 00:52:21 +00:00
Wolfgang Walther
0d1190abf7 haskellPackages.duckdb-simple: jailbreak (#528095) 2026-06-05 20:49:03 +00:00
nixpkgs-ci[bot]
c24d964453 Merge fcfb4d2c1c into haskell-updates 2026-06-05 00:55:21 +00:00
Allen Du
9ec4c8e1b6 haskellPackages.duckdb-simple: jailbreak
too strict bounds on QuickCheck <2.16
2026-06-04 15:30:54 -04:00
sternenseemann
b32a192bcf mkjson: disable doctests and switch to Codeberg (#527977) 2026-06-04 14:05:55 +00:00
Troels Henriksen
338f88c94a mkjson: disable doctests and switch to Codeberg 2026-06-04 15:43:27 +02:00
sternenseemann
a262ae9474 haskellPackages.servant-mutlipart-core: jailbreak (#527963) 2026-06-04 12:56:45 +00:00
sterni
9f367b9af0 haskellPackages.hakyll-alectryon: allow hakyll 4.17 2026-06-04 14:50:03 +02:00
sterni
9227423f57 haskellPackages.hakyll-images: drop obsolete override
Test suite was fixed in 1.3.1
2026-06-04 14:48:33 +02:00
sorki
79b85a6061 haskellPackages.servant-mutlipart-core: jailbreak
Pending issue / PR
https://github.com/haskell-servant/servant-multipart/issues/76
https://github.com/haskell-servant/servant-multipart/pull/77
2026-06-04 14:47:10 +02:00
sterni
07837352f5 git-annex: build against filepath-bytestring instead of file-io
Unfortunately, file-io >= 0.2 is required which conflicts with the core
package shipped with GHC.
2026-06-04 12:51:17 +02:00
sterni
422b020e60 git-annex: update sha256 for 10.20260525 2026-06-04 12:50:48 +02:00
nixpkgs-ci[bot]
d58b43bad8 Merge 0cc225cd89 into haskell-updates 2026-06-04 01:02:38 +00:00
nixpkgs-ci[bot]
e4e45c45d7 Merge 52383c55bc into haskell-updates 2026-06-03 01:03:22 +00:00
Wolfgang Walther
a0811c1859 haskellPackages.dataframe: unpin from 0.3.3.6 (#526717) 2026-06-02 06:42:04 +00:00
nixpkgs-ci[bot]
41dec8b399 Merge e7713b176c into haskell-updates 2026-06-02 00:57:41 +00:00
Ai-Ya-Ya
4b9529d490 haskellPackages.pinch: jailbreak
bump already merged upstream, awaiting new Hackage release
2026-06-01 23:59:36 +00:00
Ai-Ya-Ya
eca559367a haskellPackages.dataframe: unpin from 0.3.3.6
later version of dataframe removed dependency on random-1.3 so safe to
unpin
2026-06-01 18:48:15 +00:00
Wolfgang Walther
d217b14de6 haskellPackages.haskell-ci: 0.18.1 -> 0.19.20260331 (#525918) 2026-06-01 17:41:44 +00:00
nixpkgs-ci[bot]
5aafdde3a0 Merge 501880c9da into haskell-updates 2026-06-01 00:54:54 +00:00
nixpkgs-ci[bot]
9eb68607ef Merge 78058c8132 into haskell-updates 2026-05-31 00:54:34 +00:00
sterni
430963bdf1 haskellPackages.haskell-ci: 0.18.1 -> 0.19.20260331
This plus a bunch of workarounds fixes the build of haskell-ci with
Stackage Nightly.
2026-05-30 13:03:39 +02:00
Wolfgang Walther
4ca20a7582 haskellPackages.xz: drop override
Fixed in a new revision on the latest hackage bump.
2026-05-30 12:31:51 +02:00
Wolfgang Walther
39ad1cb021 haskellPackages.psqueues: drop override
Fixed in a new revision on the latest hackage bump.
2026-05-30 12:30:57 +02:00
Wolfgang Walther
6ad984ce3d haskellPackages.bitwise: drop override
Fixed in a new revision on the latest hackage bump.
2026-05-30 12:30:31 +02:00
sternenseemann
8b0587a6d1 haskellPackages.pdftotext: fix build (#525219) 2026-05-30 10:17:08 +00:00
sterni
668847dd15 haskellPackages.hoogle: unpin
This pin should _not_ have survived this long!
2026-05-30 11:42:25 +02:00
Wolfgang Walther
40f0c70593 postgrest: fix build (#524050) 2026-05-30 08:48:06 +00:00
nixpkgs-ci[bot]
265fda252f Merge ce8325fa0e into haskell-updates 2026-05-30 00:50:33 +00:00
sterni
e1eeed9ea6 release-haskell.nix: test haddock-{api,library} on GHC < 9.12
At least where possible.
2026-05-29 12:45:02 +02:00
sterni
d3928686c3 haskell.packages.ghc96.haddock-api: ignore overly strict bounds 2026-05-29 12:45:02 +02:00
sterni
fb629a8712 haskell.packages.ghc94.haddock-{api,library}: provide matching versions
GHC >= 9.12 ships these libraries as a core package, so we need to manually
pick them for older package sets. Given that they depend on the ghc library,
they actually need to match.

The broken flag on haddock-api is pretty much bogus now, as it isn't
even built as part of the main package set anymore (but with ghc as a
core pkg), but haskell.packages.ghc9{8,10}.haddock-api need to be marked
as broken since no releases compatible with GHC 9.10 or 9.8 have been
made to Hackage.
2026-05-29 12:44:22 +02:00
sterni
1fa9545db7 haskell.packages.ghc94.file-io: don't try to provide
file-io depends on unix >= 2.8 which isn't included with GHC 9.4, so we
can't properly build file-io in this package set (without making it
inconsist). Our best shot at making packages “just work” is hoping the
use Cabal conditionals to depend on file-io, so file-io doesn't actually
wind up being necessary for GHC 9.4.

If file-io is absolutely necessary, manual package specific intervention
will be necessary either way.
2026-05-29 12:42:44 +02:00
sterni
7b203a8cdf haskell.packages.ghc9{0,4,6}.semaphore-compat: keep using 1.0.0
semaphore-compat 2.0.0 has just been released, but no GHC ships it as
a core package yet, so using 1.0.0 for GHC <9.8 makes more sense as it
matches Stackage Nightly.
2026-05-29 12:42:43 +02:00
sternenseemann
3080e495c5 haskellPackages.amazonka: fix build (#525212) 2026-05-29 09:53:03 +00:00
nixpkgs-ci[bot]
41a68a1180 Merge 7b97a86791 into haskell-updates 2026-05-29 00:53:02 +00:00
Marc Scholten
2c84961290 haskellPackages.pdftotext: fix build 2026-05-28 17:35:29 +01:00
Marc Scholten
eb378a86bf haskellPackages.amazonka: fix build 2026-05-28 15:59:22 +01:00
sternenseemann
b8880df8ac haskell.packages.ghc902Binary: fix evaluation of package set (#496292) 2026-05-28 10:49:59 +00:00
sternenseemann
79a87d6750 haskell.packages.ghc902Binary: fix evaluation of package set
These attributes need to be present, so that callPackage doesn't fail
with an unrecoverable error on some members of the package set. This
is not necessary for any package Hydra builds, but helps for listing/
inspecting the package set.
2026-05-28 12:40:26 +02:00
sternenseemann
61b9e0b5f4 haskell.packages.microhs: fix eval after bump to nightly (#522940) 2026-05-28 10:28:38 +00:00
sternenseemann
2cb1137ad8 [haskell-updates] haskellPackages: stackage Nightly 2026-05-16 -> Nightly 2026-05-27 (#525157) 2026-05-28 10:24:12 +00:00
sterni
dc341cc322 haskell.packages.microhs: fix eval after bump to nightly 2026-05-28 12:23:16 +02:00
sternenseemann
7ef227eef6 haskellPackages.ghc-typelits-natnormalise: fix tests (#524100) 2026-05-28 10:17:40 +00:00
sterni
df2259de34 haskellPackages.os-string_2_0_10: drop obsolete jailbreak 2026-05-28 12:12:18 +02:00
sterni
fbfe792c92 haskellPackages: stackage Nightly 2026-05-16 -> Nightly 2026-05-27
all-cabal-hashes: 2026-05-16T18:12:46Z -> 2026-05-28T09:17:22Z

(generated by maintainers/scripts/haskell/update-package-set.sh)
2026-05-28 12:07:57 +02:00
nixpkgs-ci[bot]
18c743b5c9 Merge 8be06063cd into haskell-updates 2026-05-28 00:46:19 +00:00
Marc Scholten
1912d24658 haskellPackages.ghc-typelits-natnormalise: fix tests
Tests spawn ghc with -fplugin and need the package's in-place package database in NIX_GHC_PACKAGE_PATH_FOR_TEST.

Put the override in configuration-nix.nix so it applies across GHC package sets.

Assisted-by: OpenAI Codex (GPT-5)
2026-05-27 10:42:28 +01:00
nixpkgs-ci[bot]
8b3bed966a Merge c0523a4c8f into haskell-updates 2026-05-27 00:51:00 +00:00
nixpkgs-ci[bot]
8ca5572327 Merge 0a6619d2fd into haskell-updates 2026-05-26 01:34:21 +00:00
nixpkgs-ci[bot]
f1cd3a542b Merge 3ab9d06032 into haskell-updates 2026-05-26 00:48:54 +00:00
Wolfgang Walther
28ea7d3e94 postgrest: fix build
text-builder-dev 0.3.10 needs lawful-conversions < 0.2.

postgrest itself still depends on the older insert-ordered-containers <
0.3, but swagger2 - despite trying to provide a "compat" layer - fails
to build with that, so we pin both of them.
2026-05-25 16:51:13 +02:00
nixpkgs-ci[bot]
015d2be85f Merge 7e18ec5706 into haskell-updates 2026-05-25 14:15:27 +00:00
nixpkgs-ci[bot]
dcd5f66215 Merge 68d9bb691b into haskell-updates 2026-05-25 00:50:42 +00:00
nixpkgs-ci[bot]
c990defdc1 Merge 89afca31a7 into haskell-updates 2026-05-24 00:49:43 +00:00
nixpkgs-ci[bot]
ef80ea96c0 Merge ee4a6d835b into haskell-updates 2026-05-23 00:48:26 +00:00
nixpkgs-ci[bot]
70b3bb6148 Merge 90b4a6bcd3 into haskell-updates 2026-05-22 00:49:41 +00:00
Michael Daniels
9f87b41bbc Merge commit '8d0a7d4c0437cc1e5349d3dabde379c5e2a66305' into haskell-updates 2026-05-21 17:04:36 -04:00
Michael Daniels
9eab5d0982 Merge commit '4e39fb70d8cff0e9ffb89217d731c9b82af6473e' into haskell-updates 2026-05-19 21:10:08 -04:00
Wolfgang Walther
31b3654bd0 haskellPackages: various jailbreaks for QuickCheck 2.16 (#521243) 2026-05-18 09:51:21 +00:00
Wolfgang Walther
fd7118d37f haskell.packages.ghc{94,96,98}.os-string: allow QuickCheck 2.16 2026-05-18 11:42:42 +02:00
Wolfgang Walther
3f0c2996b0 haskellPackages.test-framework: run tests 2026-05-18 11:42:41 +02:00
Wolfgang Walther
58545c6507 haskellPackages.finite-typelits: allow QuickCheck 2.16 2026-05-18 11:42:06 +02:00
Wolfgang Walther
bd20e4d544 haskellPackages.binary-instances: allow QuickCheck 2.16 2026-05-18 11:38:35 +02:00
Wolfgang Walther
40fdae7a02 haskellPackages.proto-lens-arbitrary: update comment 2026-05-18 11:38:34 +02:00
Wolfgang Walther
4dfddc5e2d haskellPackages.hw-prim: update comment 2026-05-18 11:38:33 +02:00
Wolfgang Walther
a42cf3de47 haskellPackages.Unique: update comment 2026-05-18 11:38:32 +02:00
Wolfgang Walther
98472212df haskellPackages.hspec-core: update comment
Upstream issue is resolved, QuickCheck comment outdated - but when I try
to enable the tests, I get infinite recursion.
2026-05-18 11:38:31 +02:00
Wolfgang Walther
1166f6d5fe haskellPackages.xz: update comment 2026-05-18 11:38:30 +02:00
Wolfgang Walther
3100f81d11 haskellPackages.hgmp: drop jailbreak & unbreak
Builds fine for me.
2026-05-18 11:38:30 +02:00
Wolfgang Walther
cfae19b0e2 haskellPackages.io-sim: run tests 2026-05-18 11:38:29 +02:00
Wolfgang Walther
4c79be7954 haskellPackages.hedgehog-classes: allow hedgehog 1.6 2026-05-18 11:38:28 +02:00
Wolfgang Walther
a5d168008d haskellPackages.algebraic-graphs: allow QuickCheck 2.16 2026-05-18 11:38:27 +02:00
Wolfgang Walther
8960ba3747 haskellPackages.lzma: allow QuickCheck 2.16 2026-05-18 11:38:26 +02:00
Wolfgang Walther
4bac4c007b haskellPackages.bitwise: allow QuickCheck 2.16 2026-05-18 11:38:24 +02:00
Wolfgang Walther
449e33902d haskellPackages.fgl: allow QuickCheck 2.16 2026-05-18 11:38:24 +02:00
Wolfgang Walther
cfb525e8c7 haskellPackages.uuid: allow QuickCheck 2.16 2026-05-18 11:38:23 +02:00
Wolfgang Walther
90e108c717 haskellPackages.nix-derivation: allow QuickCheck 2.16 2026-05-18 11:38:22 +02:00
Wolfgang Walther
a9c7731b36 haskellPackages.http-api-data: allow QuickCheck 2.16 2026-05-18 11:38:21 +02:00
Wolfgang Walther
0e972a63ef haskellPackages.psqueues: allow QuickCheck 2.16 2026-05-18 11:38:19 +02:00
Wolfgang Walther
db6cdf8674 haskellPackages.{attoparsec,optparse-applicative,vecotr}: add upstream issue for QuickCheck 2.16 2026-05-18 11:38:18 +02:00
Wolfgang Walther
83742b85ed haskellPackages.criterion: drop patch
Already applied.
2026-05-18 11:36:57 +02:00
Wolfgang Walther
7fe7f911c5 haskellPackages.algebraic-graphs: drop patch
Already applied upstream.
2026-05-18 10:20:46 +02:00
Wolfgang Walther
379b9966b6 haskellPackages.pandoc: drop patches
These are already applied after the update.
2026-05-18 10:20:45 +02:00
Michael Daniels
8e147a7423 Merge commit 'c45cb29917167adb9ef5912b4bd93692cd19073e' into haskell-updates 2026-05-17 20:57:31 -04:00
sterni
e78b52efb2 haskell.packages.ghc914: drop obsolete package upgrades
We use these version by default now.
2026-05-17 15:51:05 +02:00
sternenseemann
9db26c0d78 maintainers/haskell/eval-pkg-sets.sh: add script for checking eval (#510902) 2026-05-17 13:14:33 +00:00
Wolfgang Walther
44c90f8b11 haskell.compiler.ghc{96,98,…}: drop obsolete workaround on darwin (#520191) 2026-05-17 12:41:08 +00:00
Wolfgang Walther
6ae08b4b8c haskellPackages.hpc-codecov: run obsolete override
The upstream issue has been resolved.
2026-05-17 14:38:47 +02:00
Wolfgang Walther
e71086f1ad haskellPackages: stackage LTS 24.38 -> Nightly 2026-05-16 / ghc: 9.10 -> 9.12 (#521235) 2026-05-17 12:20:08 +00:00
Wolfgang Walther
a9a7b4af3b haskellPackages.ihp{,-*}: remove overrides
hasql had been updated in the Stackage bump to Nightly, so we can just
unmark all of these at the top-level.
2026-05-17 14:08:10 +02:00
Wolfgang Walther
6e6ee420cc haskell.packages.ghc910.stack: fix eval 2026-05-17 14:05:11 +02:00
Wolfgang Walther
4f5821131d haskell.packages.ghc910.ghc-exactprint: pin 1.10
This was previously pinned via Stackage, but the update to Nightly
bumped the default to 1.12, which matches GHC 9.12.
2026-05-17 14:05:10 +02:00
Wolfgang Walther
7c90da01b9 haskellPackages: stackage LTS 24.38 -> Nightly 2026-05-16
all-cabal-hashes: 2026-04-24T19:35:23Z -> 2026-05-16T18:12:46Z

(generated by maintainers/scripts/haskell/update-package-set.sh)

Includes all manual changes required to eval and run cabal2nix-unstable
on this branch.
2026-05-17 13:57:57 +02:00
Wolfgang Walther
87258e4b4c maintainers/scripts/haskell/update-stackage: switch to Nightly
Switching to Nightly to start the upgrade process to GHC 9.12. We'll
eventually switch back to LTS once Stackage 25 is released.

Needs to be a separate commit, otherwise the script itself won't run.
2026-05-17 12:27:13 +02:00
Wolfgang Walther
07855b2421 ghc: 9.10 -> 9.12
Changing the default version of GHC ahead of switching to Stackage
Nightly in the next commits.
2026-05-17 12:27:07 +02:00
Wolfgang Walther
0ec79f0885 haskellPackages: regenerate hackage-packages
Generated by maintainers/scripts/haskell/regenerate-hackage-packages.sh
2026-05-17 11:58:18 +02:00
sterni
9adad48243 haskell.compiler.ghc{96,98,…}: drop obsolete workaround on darwin
The hadrian bindist configure script checks for the environment
variables we already set since https://gitlab.haskell.org/ghc/ghc/-/merge_requests/11649
This change has been backported to 9.6.2 and 9.8.2, so all hadrian
built GHCs we package are fixed.
2026-05-17 11:30:40 +02:00
Wolfgang Walther
2e0690adfb Merge commit 'f9710d15003bad7a6ed5f1c14229164fac2f1458' into haskell-updates 2026-05-17 10:48:26 +02:00
Wolfgang Walther
e9724bc92f git-annex: remove tasty workaround (#520973) 2026-05-17 08:37:33 +00:00
sterni
3b2f54505e git-annex: parallelize test suite
Uses git-annex custom mechanism which deals global state correctly
2026-05-16 17:20:08 +02:00
sterni
5498d6a4fe git-annex: remove tasty workaround
Has been fixed upstream
2026-05-16 17:19:28 +02:00
sternenseemann
b0f9043b9f haskell.compiler.ghcHEAD: 9.15.20260322 -> 10.1.20260513 (#520202) 2026-05-16 10:05:13 +00:00
sterni
fcd62a690f haskell.compiler.ghcHEAD: 9.15.20260322 -> 10.1.20260513 2026-05-14 22:11:54 +02:00
sternenseemann
fe8e3efa4f maintainers/haskell/eval-pkg-sets.sh: add script for checking eval
This checks the eval of all package sets, even those neither CI nor
Hydra will evaluate (completely).
2026-04-19 23:17:45 +02:00
1173 changed files with 46108 additions and 50246 deletions

View File

@@ -3,35 +3,6 @@
Nixpkgs provides a variety of wrapper functions that help build commonly useful derivations.
Like [`stdenv.mkDerivation`](#sec-using-stdenv), each of these build helpers creates a derivation, but the arguments passed are different (usually simpler) from those required by `stdenv.mkDerivation`.
## Arguments with finalAttrs {#trivial-builder-finalAttrs}
In parameters that reference this section, you may either pass the value itself,
or a function that produces it.
When it's a function the argument value is [`finalAttrs`] from [`mkDerivation`].
Typically both the *attributes* and *script* arguments support this, simultaneously if needed.
::: {.example #ex-trivial-builder-finalAttrs}
# Using `finalAttrs` in a build helper
```nix
runCommand "hi" (finalAttrs: { passthru.exe = "${finalAttrs.finalPackage}/bin/hi"; }) ''
mkdir -p $out/bin
substitute ${./hi.foo} $out/bin/hi --replace-fail "@foo@" ${lib.getExe foo}
''
```
This creates a package with an executable script that's in the standard `bin/` directory,
but also convenient to interpolate without reliance on `$PATH`, e.g assuming the result of the above is in binding `hi`:
```nix
''
echo START_GREETING
${hi.exe} --rude
echo END_GREETING
''
```
:::
## `runCommandWith` {#trivial-builder-runCommandWith}
@@ -52,10 +23,8 @@ runCommandWith :: {
name :: name;
stdenv? :: Derivation;
runLocal? :: Bool;
derivationArgs? :: { ... } | finalAttrs@{ finalPackage :: Derivation, ... } -> { ... };
}
-> (String | finalAttrs@{ finalPackage :: Derivation, ... } -> String)
-> Derivation
derivationArgs? :: { ... };
} -> String -> Derivation
```
### Inputs {#trivial-builder-runCommandWith-Inputs}
@@ -78,10 +47,10 @@ runCommandWith :: {
`stdenv` (Derivation)
: The [standard environment](#chap-stdenv) to use, defaulting to `pkgs.stdenv`.
`derivationArgs` (Attribute set *or* [function from `finalAttrs`](#trivial-builder-finalAttrs))
`derivationArgs` (Attribute set)
: Additional arguments for [`mkDerivation`](#sec-using-stdenv).
`buildCommand` (String *or* [function from `finalAttrs`](#trivial-builder-finalAttrs))
`buildCommand` (String)
: Shell commands to run in the derivation builder.
::: {.note}
@@ -140,10 +109,10 @@ While the type signature(s) differ from [`runCommandWith`], individual arguments
`name` (String)
: The derivation's name
`derivationArgs` (Attribute set *or* [function from `finalAttrs`](#trivial-builder-finalAttrs))
`derivationArgs` (Attribute set)
: Additional parameters passed to [`mkDerivation`]
`buildCommand` (String *or* [function from `finalAttrs`](#trivial-builder-finalAttrs))
`buildCommand` (String)
: The command(s) run to build the derivation.
@@ -933,6 +902,3 @@ produces an output path `/nix/store/<hash>-runtime-references` containing
but none of `hello`'s dependencies because those are not referenced directly
by `hi`'s output.
[`finalAttrs`]: #mkderivation-recursive-attributes
[`mkDerivation`]: #sec-using-stdenv

View File

@@ -176,7 +176,5 @@ stdenvNoCC.mkDerivation (
manpage-urls = callPackage ../tests/manpage-urls.nix { };
};
};
meta.license = lib.licenses.mit;
}
)

View File

@@ -1,47 +0,0 @@
# `installAgentSkills` {#installAgentSkills}
This hook automatically installs LLM agent skills into the proper location in `$out/share/skills/($pname|$base)/$skill/`.
Agents do not scan package outputs themselves. Expose skills via `environment.pathsToLink = [ "/share/skills" ];` and symlink the wanted `share/skills/<pname>/<skill>` directories into the agent's skill directory (e.g. `~/.claude/skills/`).
The automatic behavior of the hook can be disabled by setting the `dontInstallAgentSkills` variable to true.
Additionally, it exposes the `installSkill` function that can be used from `postInstall`
## `installSkill` {#installAgentSkills-installSkill}
The `installSkill` function takes one or two arguments: a directory to copy to the install location, and an optional base directory.
NB: passing a SKILL.md file directly as the first argument will fail as skills often contain other examples and tooling within the same directory.
### Example Usage {#installAgentSkills-installSkill-exampleusage}
```nix
{
nativeBuildInputs = [ installAgentSkills ];
postInstall = ''
installSkill skills/skill-xyz
'';
# installs to $out/share/skills/$pname/skill-xyz
# OR
postInstall = ''
installSkill skills/skill-xyz random-base
'';
# installs to $out/share/skills/random-base/skill-xyz
}
```
Where `skills/skill-xyz` may look like:
```
skills/skill-xyz:
- SKILL.md
- scripts/
- references/
- assets/
- ...
```

View File

@@ -247,9 +247,6 @@
{
"file": "hooks/haredo.section.md"
},
{
"file": "hooks/installAgentSkills.section.md"
},
{
"file": "hooks/installShellFiles.section.md"
},

View File

@@ -139,7 +139,7 @@ running NixOS integration tests on the builder (macOS 15+, M3 or newer).
```nix
{
inputs = {
nixpkgs.url = "https://channels.nixos.org/nixpkgs-26.05-darwin/nixexprs.tar.zst";
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-22.11-darwin";
darwin.url = "github:nix-darwin/nix-darwin/master";
darwin.inputs.nixpkgs.follows = "nixpkgs";
};

View File

@@ -140,9 +140,6 @@
"ex-testEqualArrayOrMap-test-function-add-cowbell": [
"index.html#ex-testEqualArrayOrMap-test-function-add-cowbell"
],
"ex-trivial-builder-finalAttrs": [
"index.html#ex-trivial-builder-finalAttrs"
],
"ex-writeShellApplication": [
"index.html#ex-writeShellApplication"
],
@@ -170,15 +167,6 @@
"inkscape-plugins": [
"index.html#inkscape-plugins"
],
"installAgentSkills": [
"index.html#installAgentSkills"
],
"installAgentSkills-installSkill": [
"index.html#installAgentSkills-installSkill"
],
"installAgentSkills-installSkill-exampleusage": [
"index.html#installAgentSkills-installSkill-exampleusage"
],
"installfonts": [
"index.html#installfonts"
],
@@ -1011,9 +999,6 @@
"treefmt": [
"index.html#treefmt"
],
"trivial-builder-finalAttrs": [
"index.html#trivial-builder-finalAttrs"
],
"typst": [
"index.html#typst",
"doc/languages-frameworks/typst.section.md#typst"

View File

@@ -47,8 +47,6 @@
- `bundlerApp` now sets `__structuredAttrs = true` for its result package.
Out-of-tree packages passing `postBuild` to `bundlerApp` should examine if their `postBuild` commands are compatible with structured attributes.
- `praat` has been updated to `7.x.x`, which changes the location of the settings file, buttons file, and plug-ins to standardized locations for each platform. This is a breaking change for plug-in writers and users of the sendpraat subroutine.
- `databricks-cli` has been updated from `0.290.2` to `1.x.x`, the first major release. OAuth tokens for interactive logins (`auth_type = databricks-cli`) are now stored in the OS-native secure store by default (Secret Service on Linux) instead of `~/.databricks/token-cache.json`; cached tokens from older versions are not migrated, so run `databricks auth login` once per profile after upgrading. To keep the previous file-backed storage, set `DATABRICKS_AUTH_STORAGE=plaintext` or add `auth_storage = plaintext` under `[__settings__]` in `~/.databrickscfg`. Additionally, the `vector_search_endpoints` DABs resource renamed `min_qps` to `target_qps` (and the `vector-search-endpoints` command renamed `--min-qps` to `--target-qps`). See the [upstream changelog](https://github.com/databricks/cli/blob/main/CHANGELOG.md) for details.
- Gradle 7 has been removed because it is end-of-life. Please [upgrade to a newer version of Gradle](https://docs.gradle.org/current/userguide/upgrading_version_7.html).
@@ -62,13 +60,8 @@
- `gotosocial` has been updated to 0.22.0. This release contains a very long database migration, which should not be cancelled or interrupted under any circumstances.
- Postgres users: Following the migration, if you encounter slowdown on Postgres specifically (ie., timing out while loading timelines) you may need to run some manual database maintenance steps. Please check https://docs.gotosocial.org/en/stable/admin/database_maintenance/#postgres.
- `lego` has been updated to 5.x, which has a changed CLI and state layout.
See [upstream's v4 to v5 CLI migration guide](https://go-acme.github.io/lego/migration/cli/) for details.
- `xsecurelock` no longer supports authentication via htaccess files (`~/.xsecurelock.pw`) or via the `pamtester` program by default. Only the recommended PAM module is supported unless rebuilt with `withHtaccess` or `withPamtester`.
- `keychain` has been updated to 3.x.x, which is a major and breaking rewrite of the program, including its CLI arguments. See [v3](https://github.com/danielrobbins/keychain/releases/tag/3.0.0) release notes for details and migration.
- `python3Packages.django-health-check` has been updated to major version 4. See its [migration guide](https://codingjoe.dev/django-health-check/migrate-to-v4/) and [changelog](https://github.com/codingjoe/django-health-check/releases/tag/4.0.0) for breaking changes.
- `jmtpfs` has been removed due to lack of maintenance and fuse3 support.
@@ -104,8 +97,6 @@
- `tengine` has been removed as it has seen seriously delayed responses to security vulnerabilities.
- `jellyfin` has been upgraded to major version 12, which contains breaking changes. See the [upstream blog post](https://jellyfin.org/posts/jellyfin-release-12.0) for more information on how to safely upgrade.
- `writeTextFile` now uses structured attributes and `passAsFile` is no longer used or supported.
- `nix-serve-ng` (and `haskellPackages.nix-serve-ng`) is now built against Lix instead of CppNix, following upstream which has switched to Lix as its supported Nix implementation.
@@ -164,8 +155,6 @@
- `pdfium` is now built from source instead of packaging prebuilt binaries. `pdfium-binaries` has been renamed to `pdfium`, and `pdfium-binaries-v8` has been removed.
- `iocaine` has been updated to `3.5.1`.
- `librest` providing 0.7 ABI was removed. `librest_1_0` providing 1.0 ABI was renamed to `librest` and `librest_1_0` was kept as an alias.
- `luaPackages.lrexlib-pcre` has been removed as part of the process to fully migrate from the end-of-life PRCE library to PCRE2. `luaPackages.lrexlib-pcre2` and multiple other versions of lrexlib can be used instead.
@@ -204,10 +193,6 @@
- netbox plugins have been moved from the python3Packages to the netboxPlugins package set.
- The `services.freenet` module has been renamed to `services.hyphanet`.
For more information, [see the project's website](https://www.hyphanet.org/freenet-renamed-to-hyphanet.html).
The `freenet` user, group and `/var/lib/freenet` data directory are renamed to `hyphanet` on systems with `system.stateVersion` at `26.11` or newer.
## Other Notable Changes {#sec-nixpkgs-release-26.11-notable-changes}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

View File

@@ -31,6 +31,7 @@ let
length
mapAttrs
mapAttrsToList
mapAttrsRecursiveCond
min
optional
optionalAttrs
@@ -253,7 +254,7 @@ let
# This function takes an empty attrset as an argument.
# It could theoretically be replaced with its body,
# but such a binding is avoided to allow for earlier garbage collection.
# but such a binding is avoided to allow for earlier grabage collection.
doCollect =
{ }:
collectModules class (specialArgs.modulesPath or "") (regularModules ++ [ internalModule ]) (
@@ -278,11 +279,7 @@ let
let
# For definitions that have an associated option
declaredConfig =
let
recurse = mapAttrs (n: v: if isOption v then v.value else recurse v);
in
recurse options;
declaredConfig = mapAttrsRecursiveCond (v: !isOption v) (_: v: v.value) options;
# If freeformType is set, this is for definitions that don't have an associated option
freeformConfig =
@@ -567,23 +564,12 @@ let
modulesPath:
{ disabled, modules }:
let
isDisabledModule = isDisabled modulesPath disabled;
keyFilter = filter (attrs: !isDisabledModule attrs);
keyFilter = filter (attrs: !isDisabled modulesPath disabled attrs);
in
catAttrs "module" (
genericClosure (
if disabled == [ ] then
{
startSet = modules;
operator = attrs: attrs.modules;
}
else
{
startSet = keyFilter modules;
operator = attrs: keyFilter attrs.modules;
}
)
);
catAttrs "module" (genericClosure {
startSet = keyFilter modules;
operator = attrs: keyFilter attrs.modules;
});
toGraph =
modulesPath:
@@ -645,28 +631,6 @@ let
: 3\. Function argument
*/
unifyModuleSyntax =
let
attrsToRemove = [
"_class"
"_file"
"key"
"disabledModules"
"imports"
"options"
"config"
"meta"
"freeformType"
];
shorthandAttrsToRemove = [
"_class"
"_file"
"key"
"disabledModules"
"require"
"imports"
"freeformType"
];
in
file: key: m:
let
addMeta =
@@ -690,7 +654,17 @@ let
in
if m ? config || m ? options then
let
badAttrs = removeAttrs m attrsToRemove;
badAttrs = removeAttrs m [
"_class"
"_file"
"key"
"disabledModules"
"imports"
"options"
"config"
"meta"
"freeformType"
];
in
if badAttrs != { } then
throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute."
@@ -716,7 +690,17 @@ let
disabledModules = m.disabledModules or [ ];
imports = m.require or [ ] ++ m.imports or [ ];
options = { };
config = addFreeformType (removeAttrs m shorthandAttrsToRemove);
config = addFreeformType (
removeAttrs m [
"_class"
"_file"
"key"
"disabledModules"
"require"
"imports"
"freeformType"
]
);
};
applyModuleArgsIfFunction =
@@ -892,13 +876,15 @@ let
# We're descending into attribute name.
let
loc = prefix ++ [ name ];
defns = pushedDownDefinitionsByName.${name} or [ ];
defns' = rawDefinitionsByName.${name} or [ ];
isOptionDecl =
optionDecls = filter (
m:
m.options ? _type
&& (m.options._type == "option" || throwDeclarationTypeError loc m.options._type m._file);
&& (m.options._type == "option" || throwDeclarationTypeError loc m.options._type m._file)
) decls;
in
if all isOptionDecl decls then
if length optionDecls == length decls then
let
opt = fixupOptionType loc (mergeOptionDecls loc decls);
in
@@ -906,35 +892,7 @@ let
matchedOptions = evalOptionValue loc opt defns';
unmatchedDefns = [ ];
}
# this may look like duplicate computations are performed, but testing
# with a minimal NixOS config (defined below):
#
# 1. in 87% of cases, the above `all isOptionDecl decls` passes and we
# short-circuit
# 2. In 12% of cases, there's only one decl and we short-circuit
# 3. in another 1% of cases, we loop again and short-circuit when
# `any isOptionDecl decls` fails
# 4. In the final case, we pass the `any` and have to refilter. This
# only triggers in 1 of the 48000 calls to this function.
#
# The minimal config was defined with this expression:
#
# let nixos = import ./nixos/lib/eval-config.nix {
# modules = [
# ./nixos/modules/profiles/minimal.nix
# {
# fileSystems."/" = {
# device = "/dev/sda1";
# fsType = "ext4";
# };
# boot.loader.grub.devices = [ "/dev/sda" ];
# }
# ];
# }; in nixos.config.system.build.toplevel
else if length decls != 1 && any isOptionDecl decls then
let
optionDecls = filter isOptionDecl decls;
in
else if optionDecls != [ ] then
if
all (x: x.options.type.name or null == "submodule") optionDecls
# Raw options can only be merged into submodules. Merging into
@@ -962,7 +920,7 @@ let
(head optionDecls).options.type.description or "<no description>"
}' does not support nested options.\n${showRawDecls loc nonOptions}"
else
mergeModules' loc decls (pushedDownDefinitionsByName.${name} or [ ])
mergeModules' loc decls defns
) declsByName;
matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
@@ -1051,17 +1009,19 @@ let
: 2\. Function argument
*/
mergeOptionDecls =
loc:
loc: opts:
foldl'
(
res: opt:
let
t = res.type;
t' = opt.options.type;
mergedType = t.typeMerge t'.functor;
typesMergeable = mergedType != null;
typeSet =
if res ? type && opt.options ? type then
let
mergedType = res.type.typeMerge opt.options.type.functor;
in
if mergedType != null then
if opt.options ? type && res ? type then
if typesMergeable then
{
type = mergedType;
}
@@ -1072,7 +1032,7 @@ let
else
{ };
bothHave = k: res ? ${k} && opt.options ? ${k};
bothHave = k: opt.options ? ${k} && res ? ${k};
in
if bothHave "default" || bothHave "example" || bothHave "description" || bothHave "apply" then
# Keep in sync with the same error above!
@@ -1117,7 +1077,8 @@ let
declarations = [ ];
declarationPositions = [ ];
options = [ ];
};
}
opts;
/**
Merge all the definitions of an option to produce the final
@@ -1170,19 +1131,21 @@ let
throw "The option `${showOption loc}' is read-only, but it's set multiple times. Definition values:${showDefs separateDefs}"
else
mergeDefinitions loc opt.type defs';
# Apply the 'apply' function to the merged value. This allows options to
# yield a value computed from the definitions
value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
warnDeprecation =
if (opt.type.deprecationMessage != null) then
warn "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}"
else
x: x;
in
(
if opt.type.deprecationMessage != null then
warn "The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}" opt
else
opt
)
warnDeprecation opt
// {
value = addErrorContext "while evaluating the option `${showOption loc}':" (
# Apply the 'apply' function to the merged value. This allows options to
# yield a value computed from the definitions
if opt ? apply then opt.apply res.mergedValue else res.mergedValue
);
value = addErrorContext "while evaluating the option `${showOption loc}':" value;
inherit (res.defsFinal') highestPrio;
definitions = catAttrs "value" res.defsFinal;
files = catAttrs "file" res.defsFinal;
@@ -1222,16 +1185,49 @@ let
# Merge definitions of a value of a given type.
mergeDefinitions = loc: type: defs: rec {
defsFinal' =
let
# Process mkMerge and mkIf properties.
defsNormalized = concatMap (
m:
map (
value:
if value._type or null == "definition" then
value
else
{
inherit (m) file;
inherit value;
}
) (addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
) defs;
# Process mkOverride properties.
defsFiltered = filterOverrides' defsNormalized;
# Sort mkOrder properties.
defsSorted =
# Avoid sorting if we don't have to.
if any (def: def.value._type or "" == "order") defsFiltered.values then
sortProperties defsFiltered.values
else
defsFiltered.values;
in
# Fast path: the overwhelming majority of options have exactly one
# definition whose value carries no property wrapper
# (mkIf/mkMerge/mkOverride/mkOrder/definition). In that case the
# discharge/filter/sort pipeline below is a no-op but still allocates
# several intermediate lists and closures. Detect it up front and hand the
# original singleton straight to the type merge.
# discharge/filter/sort pipeline above is a no-op but still allocates
# several intermediate lists and closures. Detect it up front and hand
# the original singleton straight to the type merge. The let-bindings
# above are lazy and thus never forced on this branch.
if
length defs == 1
&& addErrorContext "while evaluating definitions from `${(head defs).file}':" (
!(head defs).value ? _type
&& (
let
d = head defs;
in
addErrorContext "while evaluating definitions from `${d.file}':" (
!(isAttrs d.value && d.value ? _type)
)
)
then
{
@@ -1239,33 +1235,6 @@ let
highestPrio = defaultOverridePriority;
}
else
let
# Process mkMerge and mkIf properties.
defsNormalized = concatMap (
m:
map (
value:
if value._type or null == "definition" then
value
else
{
inherit (m) file;
inherit value;
}
) (addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
) defs;
# Process mkOverride properties.
defsFiltered = filterOverrides' defsNormalized;
# Sort mkOrder properties.
defsSorted =
# Avoid sorting if we don't have to.
if any (def: def.value._type or "" == "order") defsFiltered.values then
sortProperties defsFiltered.values
else
defsFiltered.values;
in
{
values = defsSorted;
inherit (defsFiltered) highestPrio;
@@ -1377,16 +1346,13 @@ let
val;
in
cfg:
if cfg ? _type then
if cfg._type == "if" then
map (mapAttrsIfAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
else if cfg._type == "merge" then
concatMap pushDownProperties cfg.contents
else if cfg._type == "override" then
map (mapAttrsIfAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
# FIXME: handle mkOrder?
else
[ cfg ]
if cfg._type or "" == "merge" then
concatMap pushDownProperties cfg.contents
else if cfg._type or "" == "if" then
map (mapAttrsIfAttrs (n: v: mkIf cfg.condition v)) (pushDownProperties cfg.content)
else if cfg._type or "" == "override" then
map (mapAttrsIfAttrs (n: v: mkOverride cfg.priority v)) (pushDownProperties cfg.content)
# FIXME: handle mkOrder?
else
[ cfg ];
@@ -1409,16 +1375,13 @@ let
*/
dischargeProperties =
def:
if def ? _type then
if def._type == "if" then
if isBool def.condition then
if def.condition then dischargeProperties def.content else [ ]
else
throw "mkIf called with a non-Boolean condition"
else if def._type == "merge" then
concatMap dischargeProperties def.contents
if def._type or "" == "merge" then
concatMap dischargeProperties def.contents
else if def._type or "" == "if" then
if isBool def.condition then
if def.condition then dischargeProperties def.content else [ ]
else
[ def ]
throw "mkIf called with a non-Boolean condition"
else
[ def ];
@@ -1508,7 +1471,7 @@ let
fixupOptionType =
loc: opt:
if opt.type.getSubModules or null == null then
if opt ? type then opt else opt // { type = types.unspecified; }
opt // { type = opt.type or types.unspecified; }
else
opt
// {
@@ -1537,21 +1500,23 @@ let
mergeAttrDefinitionsWithPrio =
opt:
let
defsByAttr = concatLists (
concatMap (
{ value, ... }@def:
map (mapAttrsToList (
k: value: {
${k} = def // {
inherit value;
};
}
)) (pushDownProperties value)
) opt.definitionsWithLocations
defsByAttr = zipAttrs (
concatLists (
concatMap (
{ value, ... }@def:
map (mapAttrsToList (
k: value: {
${k} = def // {
inherit value;
};
}
)) (pushDownProperties value)
) opt.definitionsWithLocations
)
);
in
assert opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf";
zipAttrsWith (
mapAttrs (
k: v:
let
merging = mergeDefinitions (opt.loc ++ [ k ]) opt.type.nestedTypes.elemType v;

View File

@@ -226,9 +226,6 @@ checkConfigError 'In attrTag, each tag value must be an option, but tag int was
# types
checkConfigOutput '"ok"' config.assertions ./types.nix
# types.nullOr
checkConfigError 'A definition for option .nullableValue\.mixed. is not of type .*\. TypeError: The option .nullableValue\.mixed. is defined both null and not null, in .* and .*\.' config.nullableValue.mixed ./types.nix
# types.pathInStore
checkConfigOutput '".*/store/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv"' config.pathInStore.ok1 ./types.nix
checkConfigOutput '".*/store/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15"' config.pathInStore.ok2 ./types.nix

View File

@@ -60,10 +60,6 @@ in
};
nullableValue.list = [ { bar = [ 1 ]; } ]; # list
nullableValue.lambda = x: x; # Error
nullableValue.mixed = lib.mkMerge [
null
"foo"
]; # Error
# serializableValueWith { nullable = false; }
structuredValue.null = null; # Error

View File

@@ -1242,44 +1242,18 @@ rec {
optionDescriptionPhrase (class: class == "noun" || class == "conjunction") elemType
}";
descriptionClass = "conjunction";
check = {
__functor = _self: x: x == null || elemType.check x;
isV2MergeCoherent = true;
};
merge = {
__functor =
self: loc: defs:
let
inherit (self.v2 { inherit loc defs; }) headError value;
in
if headError.causedByMixedNulls or false then throw headError.message else value;
v2 =
{ loc, defs }:
if all (def: def.value != null) defs then
# There are no null values
if elemType.merge ? v2 then
checkV2MergeCoherence loc elemType (elemType.merge.v2 { inherit loc defs; })
else
{
value = elemType.merge loc defs;
headError = checkDefsForError elemType.check loc defs;
valueMeta = { };
}
else
# There are some null values
{
headError =
if length defs == 1 || all (def: def.value == null) defs then
null
else
{
message = "The option `${showOption loc}` is defined both null and not null, in ${showFiles (getFiles defs)}.";
causedByMixedNulls = true;
};
value = null;
valueMeta = { };
};
};
check = x: x == null || elemType.check x;
merge =
loc: defs:
let
nulls = filter (def: def.value == null) defs;
in
if nulls == [ ] then
elemType.merge loc defs
else if length nulls == length defs then
null
else
throw "The option `${showOption loc}` is defined both null and not null, in ${showFiles (getFiles defs)}.";
emptyValue = {
value = null;
};

View File

@@ -1250,11 +1250,6 @@
githubId = 2545644;
name = "Alessandro Di Federico";
};
alejandroqh = {
github = "alejandroqh";
githubId = 40313108;
name = "Alejandro Quintanar";
};
alejandrosame = {
email = "alejandrosanchzmedina@gmail.com";
matrix = "@alejandrosame:matrix.org";
@@ -6234,12 +6229,6 @@
github = "dadada";
githubId = 7216772;
};
daimond113 = {
name = "daimond113";
github = "daimond113";
githubId = 72147841;
email = "contact@daimond113.com";
};
dalance = {
email = "dalance@gmail.com";
github = "dalance";
@@ -6777,6 +6766,12 @@
githubId = 25856103;
name = "DDoSolitary";
};
dduan = {
email = "daniel@duan.ca";
github = "dduan";
githubId = 75067;
name = "Daniel Duan";
};
de11n = {
email = "nixpkgs-commits@deshaw.com";
github = "de11n";
@@ -7442,12 +7437,6 @@
githubId = 93157285;
name = "Dmitrii Stepanidenko";
};
DmitrySkibitsky = {
email = "dmitryskibitsky@gmail.com";
github = "DmitrySkibitsky";
githubId = 20288556;
name = "Dmitry Skibitsky";
};
DmitryTsygankov = {
email = "dmitry.tsygankov@gmail.com";
github = "DmitryTsygankov";
@@ -8821,11 +8810,6 @@
githubId = 965612;
name = "York Wong";
};
etiennelescot = {
github = "EtienneLescot";
githubId = 215859519;
name = "Etienne Lescot";
};
Etjean = {
email = "et.jean@outlook.fr";
github = "Etjean";
@@ -10411,7 +10395,7 @@
};
gibbert = {
email = "gbjgms@gmail.com";
github = "2gibbert";
github = "zgibberish";
githubId = 67570424;
name = "gibbert";
};
@@ -14636,11 +14620,6 @@
githubId = 6544084;
name = "Kai Harries";
};
kaistarkk = {
github = "KaiStarkk";
githubId = 1722064;
name = "KaiStarkk";
};
kalbasit = {
email = "wael.nasreddine@gmail.com";
matrix = "@kalbasit:matrix.org";
@@ -25336,14 +25315,6 @@
github = "Ruixi-rebirth";
githubId = 75824585;
};
RumBugen = {
name = "Vladislav Wanner";
email = "vladislavwanner@gmail.com";
github = "RumBugen";
githubId = 43646118;
matrix = "@rumbugen:matrix.org";
keys = [ { fingerprint = "305D 2271 3C43 2E52 FB86 7C64 6107 6951 3194 1931"; } ];
};
rumpelsepp = {
name = "Stefan Tatschner";
email = "stefan@rumpelsepp.org";
@@ -31439,11 +31410,6 @@
githubId = 28888242;
name = "WORLDofPEACE";
};
wormt = {
github = "wormt";
githubId = 209373679;
name = "wormt";
};
WoutSwinkels = {
name = "Wout Swinkels";
email = "nixpkgs@woutswinkels.com";

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash
#!nix-shell -p jq git
# shellcheck shell=bash
#
# Usage: eval-pkg-sets.sh [extra flags for nix-* commands ...]
#
# Must be executed in a git checkout of Nixpkgs.
set -euo pipefail
NIXPKGS="$(git rev-parse --show-toplevel)"
PKGSETS="$(nix-env --readonly-mode --json --drv-path -f "$NIXPKGS" -qaP -A haskell.compiler "$@" \
| jq -r 'to_entries | unique_by(.value.drvPath) .[] .key | sub("^haskell.compiler";"haskell.packages")')"
trap 'exit 1' SIGINT SIGTERM
set +e
badsets=""
for set in $PKGSETS; do
# Confirm an equivalent package set to haskell.compiler.$entry exists and is usable
if ! nix-instantiate --readonly-mode -A "$set.ghc" "$@" > /dev/null 2>&1; then
echo "Skipping $set... ($set.ghc does not evaluate)"
else
echo "Evaluating $set..."
if ! nix-env --readonly-mode -f "$NIXPKGS" -qaP --drv-path -A "$set" "$@" > /dev/null; then
badsets+="$set "
fi
fi
done
if [ -n "$badsets" ]; then
echo "Found potential eval issues in the following sets:" >&2
# shellcheck disable=SC2086
printf '%s\n' $badsets
exit 1
fi

View File

@@ -6,7 +6,7 @@
# Attention: For unknown reasons, the script can't be easily cancelled and needs to be killed manually if it shouldn't run to completion.
use std log
use std/log
let broken_config = "pkgs/development/haskell-modules/configuration-hackage2nix/broken.yaml"

View File

@@ -33,7 +33,7 @@ fi
# Stackage solver to use, LTS or Nightly
# (should be capitalized like the display name)
SOLVER=LTS
SOLVER=Nightly
# Stackage solver version, if any. Use latest if empty
VERSION=
TMP_TEMPLATE=update-stackage.XXXXXXX
@@ -105,6 +105,7 @@ sed -r \
-e '/ hledger-ui /d' \
-e '/ hledger-web /d' \
-e '/ spacecookie /d' \
-e '/ hnix-store-core /d' \
< "${tmpfile_new}" >> $stackage_config
# Explanations:
# cabal2nix, distribution-nixpkgs, jailbreak-cabal, language-nix: These are our packages and we know what we are doing.

View File

@@ -32,6 +32,5 @@ stdenv.mkDerivation {
description = "Utility to generate a Nix expression for a Perl package from CPAN";
mainProgram = "nix-generate-from-cpan";
platforms = lib.platforms.unix;
license = lib.licenses.mit;
};
}

View File

@@ -39,6 +39,5 @@ stdenv.mkDerivation {
description = "Utility for Nixpkgs contributors to check Nixpkgs for common errors";
mainProgram = "nixpkgs-lint";
platforms = lib.platforms.unix;
license = lib.licenses.mit;
};
}

View File

@@ -751,6 +751,7 @@ with lib.maintainers;
swift = {
members = [
dduan
samasaur
stephank
];

View File

@@ -15,7 +15,6 @@ An example of how to build an image:
imports = [ "${modulesPath}/image/repart.nix" ];
image.repart = {
enable = true;
name = "image";
partitions = {
"esp" = {
@@ -149,7 +148,6 @@ in
fileSystems."/".device = "/dev/disk/by-label/nixos";
image.repart = {
enable = true;
name = "image";
partitions = {
"esp" = {

View File

@@ -68,18 +68,6 @@
"module-boot-plymouth-tpm2-totp-quick-start-enable": [
"index.html#module-boot-plymouth-tpm2-totp-quick-start-enable"
],
"module-services-cliproxyapi": [
"index.html#module-services-cliproxyapi"
],
"module-services-cliproxyapi-authentication": [
"index.html#module-services-cliproxyapi-authentication"
],
"module-services-cliproxyapi-authentication-cli": [
"index.html#module-services-cliproxyapi-authentication-cli"
],
"module-services-cliproxyapi-authentication-management-api": [
"index.html#module-services-cliproxyapi-authentication-management-api"
],
"module-services-keycloak-unix-socket": [
"index.html#module-services-keycloak-unix-socket"
],

View File

@@ -161,8 +161,6 @@ Alongside many enhancements to NixOS modules and general system improvements, th
- [immich-public-proxy](https://github.com/alangrainger/immich-public-proxy), a proxy for sharing Immich albums without exposing the Immich API. Available as [services.immich-public-proxy](#opt-services.immich-public-proxy.enable).
- [Omada Software Controller](https://www.tp-link.com/us/business-networking/omada-sdn-controller/omada-software-controller), a professional and free on-premises controller for the Omada Software Defined Networking (SDN) platform, provides centralized management of Omada access points, switches and routers. Available as [services.omada](#opt-services.omada.enable).
- [Zipline](https://zipline.diced.sh/), a ShareX/file upload server that is easy to use, packed with features, and with an easy setup. Available as [services.zipline](#opt-services.zipline.enable).
- [GlitchTip](https://glitchtip.com/), an open source Sentry API compatible error tracking platform. Available as [services.glitchtip](#opt-services.glitchtip.enable).

View File

@@ -34,8 +34,6 @@
- [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).
- [Zerobyte](https://github.com/nicotsx/zerobyte), backup automation for self-hosters built on top of restic, with a web interface to schedule, manage and monitor encrypted backups. Available as [services.zerobyte](#opt-services.zerobyte.enable).
- [Cardwire](https://github.com/OpenGamingCollective/cardwire), a GPU manager for Linux that uses eBPF+LSM hooks to control GPUs. Available as [services.cardwired](#opt-services.cardwired.enable).
- [Moonlight Qt](https://moonlight-stream.org/), a client for playing your PC games on almost any device. Available as [programs.moonlight-qt](#opt-programs.moonlight-qt.enable).
@@ -62,8 +60,6 @@
- [feishin](https://github.com/jeffvli/feishin), a modern self-hosted music player. Available as [services.feishin](#opt-services.feishin.enable).
- [Aurral](https://aurral.org), a Lidarr companion for self-hosted music discovery. Available as [services.aurral](#opt-services.aurral.enable).
- [CastSponsorSkip](https://github.com/gabe565/CastSponsorSkip/), skips YouTube sponsorships (and sometimes ads) on all local Google Cast devices.
- [Stump](https://www.stumpapp.dev/), a free and open source comics, manga and digital book server with OPDS support. Available as [services.stump](#opt-services.stump.enable).
@@ -74,8 +70,6 @@
- [Freescout](https://freescout.net/), a free, open source Helpdesk and shared mailbox. Available as [services.freescout](#opt-services.freescout.enable).
- [CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI), a proxy that provides OpenAI/Gemini/Claude/Codex/Grok compatible API interfaces from OAuth-based AI CLI subscriptions. Available as [services.cliproxyapi](#opt-services.cliproxyapi.enable).
- [Lix TOML remote builders](https://docs.lix.systems/manual/lix/stable/advanced-topics/distributed-builds.html#using-a-toml-configuration), remote builder configuration using lix's TOML format. Available as [lix.buildMachines](#opt-lix.buildMachines). Note: incompatible with `nix.buildMachines`.
- [Forgejo Runner](https://forgejo.org/docs/latest/admin/actions/), a daemon for Forgejo Actions. Available as [services.forgejo-runner](#opt-services.forgejo-runner.instances).
@@ -102,8 +96,6 @@
- [vellum](https://github.com/greyxp1/vellum) is a live screen annotation overlay for Wayland. Available as [programs.vellum](#opt-programs.vellum.enable).
- [iocaine](https://git.madhouse-project.org/iocaine/iocaine) is a defense mechanism against unwanted scrapers. Available as [services.iocaine](#opt-services.iocaine.enable).
- [stash-clipboard](https://github.com/NotAShelf/stash), a Wayland clipboard "manager" with fast persistent history and multi-media support. Available as [services.stash-clipboard](#opt-services.stash-clipboard.enable).
- [OO7](https://github.com/linux-credentials/oo7) is a desktop-agnostic Secret Service provider. Available as [services.oo7](#opt-services.oo7.enable)
@@ -158,12 +150,6 @@
- `boot.vesa` has been removed. It was deprecated in 2020 because Xorg now works better with kernel modesetting. If you still need the legacy VESA 800x600 fallback, set `boot.kernelParams = [ "vga=0x317" "nomodeset" ];` directly.
- `security.acme` now uses `lego` 5.x.
Existing ACME account state is migrated automatically.
If you pass raw `lego` flags through `security.acme.*.extraLegoFlags`, `security.acme.*.extraLegoRunFlags`, or `security.acme.*.extraLegoRenewFlags`, update them for the `lego` 5.x CLI.
In particular, `lego renew` has been replaced by the renewal mode of `lego run`.
The certificate identifiers formed by `domain` and `extraDomainNames` must be unique and canonical to avoid repeated renewals. Use IDNA A-labels for internationalized domain names and RFC 5952 notation for IPv6 addresses.
- `authentik` has been updated to 2026.5.3, which changes the default listen address from `0.0.0.0` to `[::]`.
IPv4-only deployments might need to adjust their listen settings.
Deployments running the server and worker in the same network namespace must also set at least the worker
@@ -183,8 +169,6 @@
- `services.pid-fan-controller` no longer provides deep configuration rewriting and adheres now fully to RFC42.
- `strongSwan` has been updated to 6.1.0, which defaults to only accepts IKEv2 connections as responder.
- The `extraArgs` and `check` arguments to `nixos/lib/eval-config.nix` (and therefore to `lib.nixosSystem`) have been removed after being deprecated with a warning since 2021. Passing them is now an evaluation error. Instead of `extraArgs`, set `config._module.args`; instead of `check = false`, set `config._module.check = false`. The `extraArgs` attribute on the resulting configuration has been removed as well.
- Rustical migrates from `settings.http.host` and `settings.http.port` to `settings.http.bind` to support UNIX domain sockets as well as TCP sockets in one setting.
@@ -258,8 +242,6 @@
- The papra NixOS module is now hardening the systemd unit by default. If this breaks any of the configured directories, please reconfigure them through `services.papra.environment` to enable sandbox passthrough.
- The `image/repart.nix` module now requires users to explicitly enable its use via `image.repart.enable`.
- `services.selfoss.extraConfig` and `services.selfoss.database` have been removed in favor of the structured [](#opt-services.selfoss.settings) option. When moving the `database` options to `settings`, you should also switch to the upstream naming:
- `type` → [`db_type`](#opt-services.selfoss.settings.db_type)
@@ -336,9 +318,6 @@
Migrating sites to Grav 2 is a [manual process](https://learn.getgrav.org/20/migration/manual-migration) with this package since the migration plugin cannot modify the Nix store.
The [`services.grav.package`](#opt-services.grav.package) option defaults to `pkgs.grav_2` if [`system.stateVersion`](#opt-system.stateVersion) >=26.11.
- The implementation of [`services.btrfs.autoScrub`](#opt-services.btrfs.autoScrub.enable) has been refactored to use systemd templates.
As part of this change, mountpoints to be scrubbed are now automatically mounted (if not already mounted) when the unit is started.
- `services.plausible` can now again seed an initial admin user declaratively via [`services.plausible.adminUser.email`](#opt-services.plausible.adminUser.email).
This makes fully declarative deployments safer: Otherwise the user needed to either accept Plausible's unauthenticated "first launch" setup wizard, which lets anyone reaching the instance create the first admin account, or do more work (deploying with NixOS's default binding to `localhost` without exposing it publicly, going through the wizard, and then deploying Plausible exposed to the Internet).
This option was previously removed with NixOS 25.05 due to an upstream Plausible change making declarative admin creation more difficult, but this change re-implements the admin creation directly.

View File

@@ -52,7 +52,6 @@ rec {
# Pin virt-11.0 to avoid gic-version=3 that works on MacOS 15+ only.
# FIXME: Revert to `virt` after minimal supported macos is 15+.
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt-11.0,accel=${accel "hvf"} -cpu max";
x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine type=q35,accel=${accel "hvf"} -cpu max";
};
};

View File

@@ -1,83 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkDefault
mkEnableOption
mkIf
mkOption
optional
types
;
cfg = config.hardware.ipu7;
in
{
options.hardware.ipu7 = {
enable = mkEnableOption "support for Intel IPU7/MIPI cameras";
platform = mkOption {
type = types.enum [
"ipu7x"
"ipu75xa"
];
description = ''
Choose the version for your hardware platform. The IPU reports which one
it is through its PCI ID, visible as the Multimedia controller in lspci.
- ipu7x (Lunar Lake, PCI 8086:645d)
Sensor list: https://github.com/intel/ipu7-camera-hal/tree/main/config/linux/ipu7x/sensors
- ipu75xa (Panther Lake, PCI 8086:b05d)
Sensor list: https://github.com/intel/ipu7-camera-hal/tree/main/config/linux/ipu75xa/sensors
'';
};
};
config = mkIf cfg.enable {
# Kernels >= 6.17 ship an IPU7 core and ISys in drivers/staging/media/ipu7,
# but no PSys, so they cannot drive the hardware ISP that the camera HAL
# needs. ipu7-drivers supplies just the PSys module (intel-ipu7-psys), which
# has no in-tree counterpart, and links it against the in-tree core and ISys
# that already enumerate the sensor.
boot.extraModulePackages = with config.boot.kernelPackages; [
ipu7-drivers
];
hardware.firmware = with pkgs; [
ipu7-camera-bins
ivsc-firmware
];
services.udev.extraRules = ''
SUBSYSTEM=="intel-ipu7-psys", MODE="0660", GROUP="video"
'';
services.v4l2-relayd.instances.ipu7 = {
enable = mkDefault true;
cardLabel = mkDefault "Intel MIPI Camera";
extraPackages =
with pkgs.gst_all_1;
optional (cfg.platform == "ipu7x") icamerasrc-ipu7x
++ optional (cfg.platform == "ipu75xa") icamerasrc-ipu75xa;
input = {
pipeline = "icamerasrc";
# REVIEW from https://edc.intel.com/content/www/us/en/secure/design/confidential/products/platforms/details/lunar-lake-mx/core-ultra-200v-series-processors-datasheet-volume-1-of-2/camera-integrated-isp/
# Output Formats - NV12, NV16, I420, M420, YUY2, YUYV, P010, P016
format = "NV12";
};
};
};
}

View File

@@ -131,7 +131,6 @@ in
];
options.image.repart = {
enable = lib.mkEnableOption "systemd-repart boot image";
name = lib.mkOption {
type = lib.types.str;
@@ -314,7 +313,7 @@ in
};
config = lib.mkIf cfg.enable {
config = {
image.baseName =
let
version = config.image.repart.version;

View File

@@ -124,7 +124,7 @@ in
datadog = 76;
lighttpd = 77;
lightdm = 78;
# hyphanet = 79; # was freenet; dynamically allocated as of 2026-09-02
freenet = 79;
ircd = 80;
bacula = 81;
#almir = 82; # removed 2018-03-25, the almir package was removed in 30291227f2411abaca097773eedb49b8f259e297 during 2017-08
@@ -466,7 +466,7 @@ in
datadog = 76;
lighttpd = 77;
lightdm = 78;
# hyphanet = 79; # was freenet; dynamically allocated as of 2026-09-02
freenet = 79;
ircd = 80;
bacula = 81;
#almir = 82; # removed 2018-03-25, the almir package was removed in 30291227f2411abaca097773eedb49b8f259e297 during 2017-08

View File

@@ -130,7 +130,6 @@
./hardware/video/virtualbox.nix
./hardware/video/webcam/facetimehd.nix
./hardware/video/webcam/ipu6.nix
./hardware/video/webcam/ipu7.nix
./hardware/wooting.nix
./hardware/xone.nix
./hardware/xpad-noone.nix
@@ -855,7 +854,6 @@
./services/misc/anki-sync-server.nix
./services/misc/apache-kafka.nix
./services/misc/atuin.nix
./services/misc/aurral.nix
./services/misc/autobrr.nix
./services/misc/autofs.nix
./services/misc/autorandr.nix
@@ -873,7 +871,6 @@
./services/misc/cgminer.nix
./services/misc/clipcat.nix
./services/misc/clipmenu.nix
./services/misc/cliproxyapi.nix
./services/misc/comfyui.nix
./services/misc/confd.nix
./services/misc/conman.nix
@@ -1246,6 +1243,7 @@
./services/networking/firezone/relay.nix
./services/networking/firezone/server.nix
./services/networking/flannel.nix
./services/networking/freenet.nix
./services/networking/freeradius.nix
./services/networking/frp.nix
./services/networking/frr.nix
@@ -1274,7 +1272,6 @@
./services/networking/htpdate.nix
./services/networking/https-dns-proxy.nix
./services/networking/hylafax/default.nix
./services/networking/hyphanet.nix
./services/networking/i2p.nix
./services/networking/i2pd.nix
./services/networking/icecream/daemon.nix
@@ -1283,7 +1280,6 @@
./services/networking/imaginary.nix
./services/networking/inadyn.nix
./services/networking/inspircd.nix
./services/networking/iocaine.nix
./services/networking/iodine.nix
./services/networking/iperf3.nix
./services/networking/ircd-hybrid/default.nix
@@ -1387,7 +1383,6 @@
./services/networking/ofono.nix
./services/networking/oidentd.nix
./services/networking/oink.nix
./services/networking/omada.nix
./services/networking/onedrive.nix
./services/networking/openconnect.nix
./services/networking/openvpn.nix
@@ -1712,7 +1707,6 @@
./services/web-apps/filebrowser.nix
./services/web-apps/firefly-iii-data-importer.nix
./services/web-apps/firefly-iii.nix
./services/web-apps/flame.nix
./services/web-apps/flarum.nix
./services/web-apps/fluidd.nix
./services/web-apps/freescout.nix
@@ -1882,7 +1876,6 @@
./services/web-apps/your_spotify.nix
./services/web-apps/youtrack.nix
./services/web-apps/zabbix.nix
./services/web-apps/zerobyte.nix
./services/web-apps/zipline.nix
./services/web-apps/zitadel.nix
./services/web-servers/agate.nix

View File

@@ -225,7 +225,6 @@ in
mainProgram = "create-builder";
description = "Create a Linux builder VM for macOS";
platforms = lib.platforms.darwin;
maintainers = with lib.maintainers; [ booxter ];
};
passthru = {
# Let users in the repl inspect the config

View File

@@ -15,7 +15,10 @@
Additionally to installing `k3b` enabling this will
add `setuid` wrappers in `/run/wrappers/bin`
for both `cdrdao` and `cdrecord`.
for both `cdrdao` and `cdrecord`. On first
run you must manually configure the path of `cdrdae` and
`cdrecord` to correspond to the appropriate paths under
`/run/wrappers/bin` in the "Setup External Programs" menu.
'';
};
};
@@ -45,5 +48,6 @@
source = "${pkgs.cdrtools}/bin/cdrecord";
};
};
};
}

View File

@@ -29,13 +29,15 @@ let
builtInRemovedMsg = "This is now built-in in DMS and doesn't need additional dependencies.";
optionalPackages =
optionals cfg.enableVPN [
optionals cfg.enableSystemMonitoring [ pkgs.dgop ]
++ optionals cfg.enableVPN [
pkgs.glib
pkgs.networkmanager
]
++ optional cfg.enableDynamicTheming pkgs.matugen
++ optional cfg.enableAudioWavelength pkgs.cava
++ optional cfg.enableCalendarEvents pkgs.khal;
++ optional cfg.enableCalendarEvents pkgs.khal
++ optional cfg.enableClipboardPaste pkgs.wtype;
in
{
imports = [
@@ -45,8 +47,6 @@ in
path ++ [ "enableSystemSound" ]
) "qtmultimedia is now included on dms-shell package.")
(lib.mkRemovedOptionModule (path ++ [ "enableClipboard" ]) builtInRemovedMsg)
(lib.mkRemovedOptionModule (path ++ [ "enableSystemMonitoring" ]) builtInRemovedMsg)
(lib.mkRemovedOptionModule (path ++ [ "enableClipboardPaste" ]) builtInRemovedMsg)
];
options.programs.dms-shell = {
@@ -86,6 +86,17 @@ in
};
};
enableSystemMonitoring = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for system monitoring widgets.
This includes process list viewers and system resource monitors.
Requires: dgop
'';
};
enableVPN = mkOption {
type = types.bool;
default = true;
@@ -130,6 +141,17 @@ in
'';
};
enableClipboardPaste = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for pasting directly from the clipboard history support.
This enables pressing Shift+Return for pasting entries from the clipboard history.
Requires: wtype
'';
};
quickshell = {
package = mkPackageOption pkgs "quickshell" { };
};

View File

@@ -278,7 +278,7 @@ in
''}
# Determine current fqdn hostname
HOST=$(${lib.getExe pkgs.unixtools.hostname} --fqdn)
HOST=$(hostname --fqdn)
# Setup command line history.
# Don't export these, otherwise other shells (bash) will try to use same HISTFILE.

View File

@@ -242,6 +242,8 @@ let
+ lib.optionalString (data.csr != null) " - ${data.csr}"
+ lib.optionalString (data.profile != null) " - ${data.profile}";
certDir = mkHash hashData;
# TODO remove domainHash usage entirely. Waiting on go-acme/lego#1532
domainHash = mkHash "${lib.concatStringsSep " " extraDomains} ${data.domain}";
accountHash = (mkAccountHash acmeServer data);
accountDir = accountDirRoot + accountHash;
@@ -252,10 +254,7 @@ let
"--dns"
data.dnsProvider
]
++ lib.optionals (!data.dnsPropagationCheck) [
"--dns.propagation.disable-ans"
"--dns.propagation.disable-rns"
]
++ lib.optionals (!data.dnsPropagationCheck) [ "--dns.propagation-disable-ans" ]
++ lib.optionals (data.dnsResolver != null) [
"--dns.resolvers"
data.dnsResolver
@@ -270,7 +269,7 @@ let
else if data.listenHTTP != null then
[
"--http"
"--http.address"
"--http.port"
data.listenHTTP
]
else
@@ -310,27 +309,21 @@ let
]) extraDomains
++ data.extraLegoFlags;
# `lego run` renews when its state still contains a certificate resource. The full
# path is also a recovery path, so force renewal without an ARI `replaces`
# identifier that may refer to a stale certificate.
# Although --must-staple is common to both modes, it is not declared as a
# mode-agnostic argument in lego and thus must come after the mode.
runOpts = lib.escapeShellArgs (
[ "run" ]
++ commonOpts
++ [
"--no-random-sleep"
"--renew-force"
"--ari-disable"
]
++ lib.optionals (data.csr == null) [ "--force-cert-domains" ]
commonOpts
++ [ "run" ]
++ lib.optionals data.ocspMustStaple [ "--must-staple" ]
++ lib.optionals (data.profile != null) [ "--profile=${data.profile}" ]
++ data.extraLegoRunFlags
);
renewOpts = lib.escapeShellArgs (
[ "run" ]
++ commonOpts
++ [ "--no-random-sleep" ]
++ lib.optionals (data.csr == null) [ "--force-cert-domains" ]
commonOpts
++ [
"renew"
"--no-random-sleep"
]
++ lib.optionals data.ocspMustStaple [ "--must-staple" ]
++ lib.optionals (data.profile != null) [ "--profile=${data.profile}" ]
++ data.extraLegoRenewFlags
@@ -582,18 +575,13 @@ let
}
}
# Multiple certificates can share an account. Serialize the check and
# migration because lego v5 moves the shared key out of keys/.
exec {MIGRATION_LOCK_FD}> "${lockdir}migration-${accountHash}.lock"
${pkgs.flock}/bin/flock "$MIGRATION_LOCK_FD"
if [ -n "$(find accounts -path '*/keys/*.key' -print -quit)" ]; then
printf 'Y\n' | lego migrate --account-only --path .
fi
exec {MIGRATION_LOCK_FD}>&-
echo '${domainHash}' > domainhash.txt
# Check if the existing certificate can be renewed.
# Check if a new order is needed
# We can only renew if the list of domains has not changed.
# We also need an account key. Avoids #190493
if [ -e '${certificateKey}' ] && [ -e 'certificates/${keyName}.crt' ] && \
if cmp -s domainhash.txt certificates/domainhash.txt && [ -e '${certificateKey}' ] && \
[ -e 'certificates/${keyName}.crt' ] && \
[ -n "$(find accounts -name '${
if (data.email != null) then data.email else placeholderEmail
}.key')" ];
@@ -602,7 +590,7 @@ let
# Try to renew, and silently fail if the cert is not expired.
# Avoids #85794 and resolves #129838
if ! lego ${renewOpts} ${
if data.validMinDays != null then "--renew-days ${toString data.validMinDays}" else ""
if data.validMinDays != null then "--days ${toString data.validMinDays}" else "--dynamic"
}; then
if is_expiration_skippable out/full.pem; then
echo 1>&2 "nixos-acme: Ignoring failed renewal because expiration isn't due yet"
@@ -622,6 +610,8 @@ let
exit 10
fi
mv domainhash.txt certificates/
touch out/acme-success
# Copy all certs to the "real" certs directory
@@ -882,7 +872,7 @@ let
type = lib.types.listOf lib.types.str;
inherit (defaultAndText "extraLegoFlags" [ ]) default defaultText;
description = ''
Additional flags to pass to both `lego run` invocations.
Additional global flags to pass to all lego commands.
'';
};
@@ -890,7 +880,7 @@ let
type = lib.types.listOf lib.types.str;
inherit (defaultAndText "extraLegoRenewFlags" [ ]) default defaultText;
description = ''
Additional flags to pass to the non-forced renewal `lego run` invocation.
Additional flags to pass to lego renew.
'';
};
@@ -898,7 +888,7 @@ let
type = lib.types.listOf lib.types.str;
inherit (defaultAndText "extraLegoRunFlags" [ ]) default defaultText;
description = ''
Additional flags to pass to the forced obtain/reissue `lego run` invocation.
Additional flags to pass to lego run.
'';
};
};

View File

@@ -236,8 +236,7 @@ in
# If DynamicUser= is enabled, PrivateTmp=true is implied (and cannot be turned off).
# so disable them unless PrivateTmp=true is explicitely set.
# We're explicitely comparing to `false` here, because PrivateTmp can also be "disconnected".
${lib.optionalString (cfg.serviceConfig.PrivateTmp == false) ''
${lib.optionalString (!cfg.serviceConfig.PrivateTmp) ''
echo "InaccessiblePaths=-+/tmp" >> "$serviceFile"
echo "InaccessiblePaths=-+/var/tmp" >> "$serviceFile"
''}

View File

@@ -560,16 +560,6 @@ in
++ lib.optional (cfg.dockerHost == null) "docker.service";
wantedBy = [ "multi-user.target" ];
# Periphery shells out to `docker`, `docker compose` and `git` through `sh -c`.
path = [
pkgs.git
config.virtualisation.docker.package
]
++ lib.optionals (!cfg.disableTerminals) [
"/run/current-system/sw"
"/run/wrappers"
];
serviceConfig = {
Type = "simple";
User = cfg.user;
@@ -614,6 +604,11 @@ in
// cfg.environment
);
ExecSearchPath = lib.mkIf (!cfg.disableTerminals) [
"/run/current-system/sw/bin"
"/run/wrappers/bin"
];
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
StateDirectory = "komodo-periphery";

View File

@@ -69,8 +69,7 @@ let
cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh";
cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
strictDeps = true;
__structuredAttrs = true;
passAsFile = [ "extraEnvSh" ];
inherit (cfg) extraEnvSh package;
buildCommand = ''
@@ -81,7 +80,7 @@ let
( cat "$cassandraEnvPkg"
echo "# lines from services.cassandra.extraEnvSh: "
printf "%s" "$extraEnvSh"
cat "$extraEnvShPath"
) > "$out/cassandra-env.sh"
# Delete default JMX Port, otherwise we can't set it using env variable

View File

@@ -44,17 +44,19 @@ let
makeBinPath [
cfg.quickshell.package
compositorPkg
pkgs.glib # provides gdbus, used by the fprintd hardware probe and portal reads
]
}
${
escapeShellArgs (
[
"${cfg.package}/bin/dms-greeter"
"sh"
"${cfg.package}/share/quickshell/dms/Modules/Greetd/assets/dms-greeter"
"--cache-dir"
cacheDir
"--command"
cfg.compositor.name
"-p"
"${cfg.package}/share/quickshell/dms"
]
++ lib.optionals (cfg.compositor.customConfig != "") [
"-C"
@@ -112,7 +114,21 @@ in
options.services.displayManager.dms-greeter = {
enable = mkEnableOption "DankMaterialShell greeter";
package = lib.mkPackageOption pkgs "dms-greeter" { };
package = mkOption {
type = types.package;
default = if cfgDms.enable then cfgDms.package else pkgs.dms-shell;
defaultText = literalExpression ''
if config.programs.dms-shell.enable
then config.programs.dms-shell.package
else pkgs.dms-shell;
'';
description = ''
The DankMaterialShell package to use for the greeter.
Defaults to the package from `programs.dms-shell` if it is enabled,
otherwise defaults to `pkgs.dms-shell`.
'';
};
compositor = {
name = mkOption {

View File

@@ -1,185 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.aurral;
in
{
options = {
services.aurral = {
enable = lib.mkEnableOption "Aurral is the Lidarr companion for self-hosted music discovery";
package = lib.mkPackageOption pkgs "aurral" { };
directories = lib.mkOption {
type = lib.types.listOf lib.types.externalPath;
default = [ ];
description = ''
Directories that Aurral needs access to. Other directories won't be visible by the app.
Environment variable `DOWNLOAD_FOLDER` is added automatically.
See BindPaths in {manpage}`systemd.exec(5)`.
'';
};
dataDir = lib.mkOption {
type = lib.types.externalPath;
default = "/var/lib/aurral";
description = ''
The directory where Aurral stores its stateful data.
'';
};
port = lib.mkOption {
type = lib.types.port;
default = 3001;
description = "Port number";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Open ports in the firewall for Aurral.
'';
};
user = lib.mkOption {
type = lib.types.str;
default = "aurral";
description = ''
User account under which Aurral runs.
'';
};
group = lib.mkOption {
type = lib.types.str;
default = "aurral";
description = ''
Group under which Aurral runs.
'';
};
environment = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
example = {
DOWNLOAD_FOLDER = "/media/downloads";
TRUST_PROXY = "true";
};
description = ''
Environment variables passed to the service.
'';
};
environmentFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Environment file as defined in {manpage}`systemd.exec(5)` passed to the service.
'';
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.aurral = {
description = "Aurral";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = cfg.environment // {
AURRAL_DATA_DIR = cfg.dataDir;
PORT = toString cfg.port;
};
path = [ cfg.package ];
serviceConfig = {
Type = "simple";
ExecStart = lib.getExe cfg.package;
Restart = "on-failure";
User = cfg.user;
Group = cfg.group;
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
StateDirectory = lib.mkIf (cfg.dataDir == "/var/lib/aurral") "aurral";
WorkingDirectory = cfg.dataDir;
ReadWritePaths = "";
ProtectSystem = "strict";
BindPaths = [
cfg.dataDir
]
++ (lib.map (x: "-" + x) cfg.directories)
++ lib.optional (cfg.environment ? DOWNLOAD_FOLDER) cfg.environment.DOWNLOAD_FOLDER;
BindReadOnlyPaths = [
builtins.storeDir
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
"-/etc/resolv.conf"
]
++ lib.optionals config.services.resolved.enable [
"/run/systemd/resolve/stub-resolv.conf"
"/run/systemd/resolve/resolv.conf"
];
RestrictSUIDSGID = true;
CapabilityBoundingSet = "";
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
SocketBindDeny = "any";
SocketBindAllow = toString cfg.port;
SystemCallErrorNumber = "EPERM";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0007";
SystemCallArchitectures = "native";
ProtectProc = "invisible";
ProcSubset = "pid";
LockPersonality = true;
NoNewPrivileges = true;
DevicePolicy = "closed";
PrivateIPC = true;
PrivatePIDs = true;
ProtectClock = true;
ProtectHome = true;
ProtectKernelLogs = true;
ProtectHostname = true;
RemoveIPC = true;
RestrictRealtime = true;
RestrictNamespaces = true;
MemoryDenyWriteExecute = false;
};
confinement.enable = true;
};
systemd.tmpfiles.settings."10-aurral" = lib.mkIf (cfg.environment ? DOWNLOAD_FOLDER) {
${cfg.environment.DOWNLOAD_FOLDER}.d = {
inherit (cfg) user group;
mode = "0770";
};
};
users.users = lib.mkIf (cfg.user == "aurral") {
aurral = {
isSystemUser = true;
home = cfg.dataDir;
group = cfg.group;
};
};
users.groups = lib.mkIf (cfg.group == "aurral") {
aurral = { };
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
};
}

View File

@@ -1,55 +0,0 @@
# CLIProxyAPI {#module-services-cliproxyapi}
[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) exposes OAuth-based subscription CLIs (Claude Code, Codex, Gemini, Qwen, Grok, Antigravity) behind OpenAI/Gemini/Anthropic-compatible HTTP APIs.
Enable it with:
```nix
{
services.cliproxyapi.enable = true;
}
```
The service runs as a dedicated `cliproxyapi` user and keeps its configuration and OAuth tokens under `/var/lib/cliproxyapi`.
## Authentication {#module-services-cliproxyapi-authentication}
Provider logins use OAuth and must land in the service's `auth-dir` (`/var/lib/cliproxyapi`), which is owned by the `cliproxyapi` user. Either of the approaches below writes the token with the correct ownership, and the running service picks it up without a restart.
### Management API {#module-services-cliproxyapi-authentication-management-api}
Set a management key in [](#opt-services.cliproxyapi.settings):
```nix
{
services.cliproxyapi.settings.remote-management.secret-key._secret =
"/run/secrets/cliproxyapi-mgmt-key";
}
```
Then request an authentication URL for the desired provider and open it in a browser:
```bash
curl -H "Authorization: Bearer <management-key>" \
http://127.0.0.1:8317/v0/management/anthropic-auth-url
```
The daemon completes the OAuth flow itself and stores the token in its `auth-dir`. Authentication endpoints are available for the `anthropic`, `codex`, `xai`, `antigravity`, and `kimi` providers.
### Command-line login {#module-services-cliproxyapi-authentication-cli}
Add the package so the `cliproxyapi` binary is on `PATH`:
```nix
{
environment.systemPackages = [ config.services.cliproxyapi.package ];
}
```
Then run the login as the service user, pointing at the managed configuration:
```bash
sudo -u cliproxyapi cliproxyapi -config /var/lib/cliproxyapi/config.yaml --claude-login
```
Other providers use their matching flags, for example `--codex-login` or `--xai-login`. On a headless host, pass `-no-browser` to print the OAuth URL instead of launching a browser.

View File

@@ -1,153 +0,0 @@
{
config,
lib,
pkgs,
utils,
...
}:
let
cfg = config.services.cliproxyapi;
format = pkgs.formats.yaml { };
stateDir = "/var/lib/cliproxyapi";
configPath = "${stateDir}/config.yaml";
settings = {
auth-dir = stateDir;
}
// cfg.settings;
secretsReplacement = utils.genJqSecretsReplacement {
loadCredential = true;
} settings configPath;
port = cfg.settings.port or 8317;
in
{
options.services.cliproxyapi = {
enable = lib.mkEnableOption "CLIProxyAPI";
package = lib.mkPackageOption pkgs "cliproxyapi" { };
settings = lib.mkOption {
type = format.type;
default = { };
example = lib.literalExpression ''
{
host = "127.0.0.1";
port = 8317;
api-keys = [ { _secret = "/run/secrets/cliproxyapi-api-key"; } ];
remote-management.secret-key._secret = "/run/secrets/cliproxyapi-management-key";
}
'';
description = ''
Configuration for CLIProxyAPI. See the
[example configuration](https://github.com/router-for-me/CLIProxyAPI/blob/main/config.example.yaml)
for available options. Secret values can be loaded from files using
`._secret = "/path/to/secret";`.
'';
};
environmentFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/run/secrets/cliproxyapi.env";
description = "Environment file as defined in {manpage}`systemd.exec(5)`.";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the firewall for the specified port.";
};
user = lib.mkOption {
type = lib.types.str;
default = "cliproxyapi";
description = "User account under which CLIProxyAPI runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = "cliproxyapi";
description = "Group under which CLIProxyAPI runs.";
};
};
config = lib.mkIf cfg.enable {
users.users = lib.mkIf (cfg.user == "cliproxyapi") {
cliproxyapi = {
isSystemUser = true;
group = cfg.group;
home = stateDir;
description = "CLIProxyAPI service user";
};
};
users.groups = lib.mkIf (cfg.group == "cliproxyapi") {
cliproxyapi = { };
};
systemd.services.cliproxyapi = {
description = "Proxy that provides OpenAI/Gemini/Claude/Codex/Grok compatible API interfaces";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
preStart = secretsReplacement.script;
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
StateDirectory = "cliproxyapi";
StateDirectoryMode = "0700";
WorkingDirectory = stateDir;
ExecStart = "${lib.getExe cfg.package} -config ${configPath}";
Restart = "on-failure";
RestartSec = 5;
LoadCredential = secretsReplacement.credentials;
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
# Hardening
CapabilityBoundingSet = "";
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
ProtectProc = "invisible";
ProcSubset = "pid";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictSUIDSGID = true;
RestrictRealtime = true;
RemoveIPC = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ port ];
};
};
meta = {
doc = ./cliproxyapi.md;
maintainers = [ lib.maintainers.anish ];
};
}

View File

@@ -111,13 +111,7 @@ in
ExecStart = toString [
(lib.getExe' cfg.package "llama-server")
(lib.cli.toCommandLine (optionName: {
option =
if lib.hasPrefix "-" optionName then
optionName
else if builtins.stringLength optionName > 1 then
"--${optionName}"
else
"-${optionName}";
option = if builtins.stringLength optionName > 1 then "--${optionName}" else "-${optionName}";
sep = " ";
explicitBool = false;
formatArg = lib.generators.mkValueStringDefault { };

View File

@@ -0,0 +1,51 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.freenet;
varDir = "/var/lib/freenet";
in
{
options = {
services.freenet = {
enable = lib.mkEnableOption "Freenet daemon";
nice = lib.mkOption {
type = lib.types.ints.between (-20) 19;
default = 10;
description = "Set the nice level for the Freenet daemon";
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.freenet = {
description = "Freenet daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = lib.getExe pkgs.freenet;
User = "freenet";
UMask = "0007";
WorkingDirectory = varDir;
Nice = cfg.nice;
};
};
users.users.freenet = {
group = "freenet";
description = "Freenet daemon user";
home = varDir;
createHome = true;
uid = config.ids.uids.freenet;
};
users.groups.freenet.gid = config.ids.gids.freenet;
};
meta.maintainers = with lib.maintainers; [ nagy ];
}

View File

@@ -120,93 +120,6 @@ in
example = "/var/lib/headplane";
};
proxy_auth = mkOption {
type = types.nullOr (
types.submodule {
options = {
enabled = mkEnableOption ''
delegating Headplane authentication to a trusted reverse proxy
instead of logging in through Headplane directly. Identity
headers are only trusted on requests whose client IP matches
`allowed_cidrs`; all Headscale API calls then use
`headscale.api_key_path`
'';
allowed_cidrs = mkOption {
type = types.listOf types.str;
default = [
"127.0.0.1/32"
"::1/128"
];
description = ''
Client CIDRs allowed to authenticate via the configured proxy
headers.
'';
example = [ "10.0.0.0/8" ];
};
trusted_proxy_cidrs = mkOption {
type = types.listOf types.str;
default = [
"127.0.0.1/32"
"::1/128"
];
description = ''
Direct proxy CIDRs trusted to supply `ip_header`.
'';
example = [ "127.0.0.1/32" ];
};
ip_header = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Header containing the original client IP, such as
`X-Forwarded-For` or `X-Real-IP`. Only read when the direct
socket peer matches `trusted_proxy_cidrs`.
'';
example = "X-Forwarded-For";
};
user_header = mkOption {
type = types.str;
default = "Remote-User";
description = ''
Header containing the stable authenticated user identity.
'';
example = "Remote-User";
};
email_header = mkOption {
type = types.nullOr types.str;
default = null;
description = "Optional header containing the authenticated user's email address.";
example = "Remote-Email";
};
name_header = mkOption {
type = types.nullOr types.str;
default = null;
description = "Optional header containing the authenticated user's display name.";
example = "Remote-Name";
};
picture_header = mkOption {
type = types.nullOr types.str;
default = null;
description = "Optional header containing the authenticated user's profile picture URL.";
example = "Remote-Picture";
};
};
}
);
default = null;
description = ''
Delegate Headplane authentication to a trusted reverse proxy. See the
upstream [Proxy Authentication docs](https://github.com/tale/headplane/blob/main/docs/features/proxy-auth.md).
'';
};
};
};
default = { };
@@ -532,18 +445,6 @@ in
services.headplane.settings.headscale.api_key_path must be set when the agent is enabled.
'';
}
{
assertion =
cfg.settings.server.proxy_auth == null
|| !cfg.settings.server.proxy_auth.enabled
|| cfg.settings.headscale.api_key_path != null;
message = ''
services.headplane.settings.headscale.api_key_path must be set
when services.headplane.settings.server.proxy_auth.enabled is true.
Proxy authentication requires a Headscale API key to make Headscale
API calls on behalf of proxy-authenticated users.
'';
}
];
environment = {

View File

@@ -1,56 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.hyphanet;
useNewNames = lib.versionAtLeast config.system.stateVersion "26.11";
userName = if useNewNames then "hyphanet" else "freenet";
varDir = "/var/lib/${userName}";
in
{
options = {
services.hyphanet = {
enable = lib.mkEnableOption "Hyphanet daemon";
nice = lib.mkOption {
type = lib.types.ints.between (-20) 19;
default = 10;
description = "Set the nice level for the Hyphanet daemon";
};
};
};
imports = [
(lib.mkRenamedOptionModule [ "services" "freenet" ] [ "services" "hyphanet" ])
];
config = lib.mkIf cfg.enable {
systemd.services.hyphanet = {
description = "Hyphanet daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = lib.getExe pkgs.hyphanet;
User = userName;
UMask = "0007";
WorkingDirectory = varDir;
Nice = cfg.nice;
};
};
users.users.${userName} = {
group = userName;
description = "Hyphanet daemon user";
home = varDir;
createHome = true;
};
users.groups.${userName} = { };
};
meta.maintainers = with lib.maintainers; [ nagy ];
}

View File

@@ -263,14 +263,6 @@ in
types.submodule {
inherit freeformType;
options = {
type = lib.mkOption {
type = types.str;
default = "server";
description = ''
Type of server tunnel.
See <https://docs.i2pd.website/en/latest/user-guide/tunnels/#tunnel-types>.
'';
};
host = lib.mkOption {
type = types.either types.str credType;
description = "IP address of server (on this address i2pd will send data from I2P)";
@@ -297,14 +289,6 @@ in
types.submodule {
inherit freeformType;
options = {
type = lib.mkOption {
type = types.str;
default = "client";
description = ''
Type of client tunnel.
See <https://docs.i2pd.website/en/latest/user-guide/tunnels/#tunnel-types>.
'';
};
port = lib.mkOption {
type = types.port;
description = "Port of client tunnel (on this port i2pd will receive data)";
@@ -417,8 +401,10 @@ in
gen = attr: settings: {
conf = genConfig "i2pd.conf" (credSubstituteRec attr settings);
tunconf = genTunnels "i2pd-tunnels.conf" (
lib.mapAttrs' (k: v: lib.nameValuePair "client-${k}" v) (credSubstituteRec attr cfg.clientTunnels)
// lib.mapAttrs' (k: v: lib.nameValuePair "server-${k}" v) (
lib.mapAttrs' (k: v: lib.nameValuePair "client-${k}" (v // { "type" = "client"; })) (
credSubstituteRec attr cfg.clientTunnels
)
// lib.mapAttrs' (k: v: lib.nameValuePair "server-${k}" (v // { "type" = "server"; })) (
credSubstituteRec attr cfg.serverTunnels
)
);

View File

@@ -1,226 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
any
getExe
hasPrefix
mapAttrsToList
mkIf
literalExpression
mkEnableOption
mkMerge
mkOption
mkPackageOption
optional
optionals
;
inherit (lib.types)
attrsOf
bool
listOf
nullOr
path
str
submodule
;
cfg = config.services.iocaine;
jsonFormat = pkgs.formats.json { };
hasUDSbind = any (hasPrefix "/") (
mapAttrsToList (_server: cfg: cfg.bind) (cfg.settings.server or { })
);
ifHasSettings = optional (cfg.settings != null);
hasFirewall = cfg.settings.firewall.enable;
description = "iocaine, the deadliest poison known to AI";
in
{
options.services.iocaine = {
enable = mkEnableOption description;
package = mkPackageOption pkgs "iocaine" { };
environment = mkOption {
default = { };
type = attrsOf str;
description = "Environment variables for iocaine.";
example = literalExpression ''
{
RUST_LOG = "info";
RUST_BACKTRACE = "1";
}
'';
};
settings = mkOption {
type = nullOr (submodule {
freeformType = jsonFormat.type;
options = {
firewall.enable = mkOption {
default = false;
type = bool;
description = "Enables the firewall";
example = true;
};
};
});
default = null;
description = ''
The configuration for iocaine.
See [the configuration reference](https://iocaine.madhouse-project.org/documentation/3/configuration/)
for full documentation on the fields.
'';
example = literalExpression ''
{
server.default = {
bind = "localhost:2137";
mode = "http";
use.handler-from = "default";
};
handler.default = {
settings = {
"ai-robots-txt-path" = "/etc/iocaine/data/ai.robots.txt-robots.json";
sources = {
training-corpus = [
"/data/corpus/1984.txt"
"/data/corpus/brave-new-world.txt"
];
wordlists = [ "/data/corpus/words.txt" ];
};
};
};
}
'';
};
extraSettingsPaths = mkOption {
type = listOf path;
default = [ ];
description = "Configuration paths to run iocaine with. Useful for secrets";
example = literalExpression ''
[
"/etc/iocaine/iocaine.json"
./iocaine.json
]
'';
};
};
config = mkIf cfg.enable {
environment.etc."iocaine/iocaine.json" = mkIf (cfg.settings != null) {
source = jsonFormat.generate "iocaine.json" cfg.settings;
};
systemd.services = mkMerge [
{
iocaine = {
inherit description;
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = {
HOME = "%S/home";
}
// cfg.environment;
restartTriggers =
(ifHasSettings config.environment.etc."iocaine/iocaine.json".source) ++ cfg.extraSettingsPaths;
stopIfChanged = false;
serviceConfig = {
Type = "notify";
ExecStart = toString (
[
(getExe cfg.package)
]
++ (map (path: "--config-path=${path}") (
(ifHasSettings "/etc/iocaine/iocaine.json") ++ cfg.extraSettingsPaths
))
++ [ "start" ]
);
Restart = "on-failure";
DynamicUser = true;
UMask = "0077";
LimitNOFILE = 524288;
StateDirectory = "iocaine";
WorkingDirectory = "%S/iocaine";
RuntimeDirectory = "iocaine";
ProtectSystem = "strict";
ProtectClock = true;
ProtectHostname = true;
ProtectProc = "invisible";
ProtectControlGroups = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectKernelLogs = true;
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = !hasFirewall;
SystemCallArchitectures = "native";
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = false;
NoNewPrivileges = true;
RestrictAddressFamilies =
(optionals hasUDSbind [
"AF_INET"
"AF_INET6"
"AF_UNIX"
])
++ (optionals hasFirewall [ "AF_NETLINK" ]);
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
CapabilityBoundingSet = mkIf hasFirewall [ "CAP_NET_ADMIN" ];
AmbientCapabilities = mkIf hasFirewall [ "CAP_NET_ADMIN" ];
};
};
}
(
let
iocaineDep = {
requires = [ "iocaine.service" ];
after = [ "iocaine.service" ];
serviceConfig.SupplementaryGroups = [ "iocaine" ];
};
in
{
nginx = mkIf (config.services.nginx.enable && hasUDSbind) iocaineDep;
caddy = mkIf (config.services.caddy.enable && hasUDSbind) iocaineDep;
}
)
];
};
meta = {
maintainers = with lib.maintainers; [ poz ];
};
}

View File

@@ -1,140 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.omada;
in
{
options = {
services.omada = {
enable = lib.mkEnableOption "Enable the Omada Software Controller service.";
package = lib.mkPackageOption pkgs "omada-software-controller" { };
user = lib.mkOption {
type = lib.types.str;
default = "omada";
description = ''
User under which the Omada Software Controller service runs.
'';
};
group = lib.mkOption {
type = lib.types.str;
default = "omada";
description = ''
Group under which the Omada Software Controller service runs.
'';
};
dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/omada";
description = ''
The path where the Omada Software Controller stores all data. This path must
be in sync with the omada-software-controller package (where it is hardcoded
during the build in accordance with its own `dataDir` argument).
'';
};
openFirewallDevicePorts = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to open the firewall ports required for Omada devices to communicate
with the Omada Software Controller (discovery, adoption, management, etc.).
'';
};
openFirewallWebPorts = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to open the firewall ports of the web interface (8043, 8088).
'';
};
};
};
config = lib.mkIf cfg.enable {
users.groups.${cfg.group} = { };
users.users.${cfg.user} = {
description = "Omada Software Controller user";
group = cfg.group;
home = cfg.dataDir;
createHome = true;
isSystemUser = true;
};
systemd.tmpfiles.settings."10-omada" =
lib.genAttrs
(map (dir: "${cfg.dataDir}/${dir}") [
"data"
"logs"
"properties"
"work"
])
(_: {
d = {
user = cfg.user;
group = cfg.group;
};
});
systemd.services.omada = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
description = "Omada Software Controller";
serviceConfig = {
ExecStart = "${lib.getExe cfg.package} start";
ExecStop = "${lib.getExe cfg.package} stop";
# The control script asks for confirmation (y/n) before starting when
# it detects that MongoDB was upgraded across major versions. Answer it,
# otherwise its read loop would spin forever on an EOF stdin.
StandardInput = "data";
StandardInputText = "y";
Type = "forking";
TimeoutSec = 300;
RuntimeDirectory = "omada";
RuntimeDirectoryMode = "0755";
PIDFile = "/run/omada/omada.pid";
WorkingDirectory = cfg.dataDir;
StateDirectory = baseNameOf cfg.dataDir;
User = cfg.user;
Group = cfg.group;
Environment = [
"OMADA_USER=${cfg.user}"
];
Restart = "on-failure";
};
};
networking.firewall = {
allowedUDPPorts = lib.optionals cfg.openFirewallDevicePorts [
19810 # discovery port
29810 # discovery port
];
allowedTCPPorts =
lib.optionals cfg.openFirewallDevicePorts [
29811 # management port
29812 # adoption port
29813 # upgrade port
29814 # management port
29815 # transfer port
29816 # rtty port
29817 # device management port
]
++ lib.optionals cfg.openFirewallWebPorts [
8043 # web port (HTTPS)
8088 # web port (HTTP)
];
};
};
}

View File

@@ -95,8 +95,8 @@ in
wantedBy = [ "network.target" ];
serviceConfig = {
Type = "forking";
ExecStart = "${cfg.dataDir}/vpnserver/vpnserver start";
ExecStop = "${cfg.dataDir}/vpnserver/vpnserver stop";
ExecStart = "${package}/bin/vpnserver start";
ExecStop = "${package}/bin/vpnserver stop";
};
preStart = ''
rm -rf ${cfg.dataDir}/vpnserver/vpnserver
@@ -116,8 +116,8 @@ in
wantedBy = [ "network.target" ];
serviceConfig = {
Type = "forking";
ExecStart = "${cfg.dataDir}/vpnbridge/vpnbridge start";
ExecStop = "${cfg.dataDir}/vpnbridge/vpnbridge stop";
ExecStart = "${package}/bin/vpnbridge start";
ExecStop = "${package}/bin/vpnbridge stop";
};
preStart = ''
rm -rf ${cfg.dataDir}/vpnbridge/vpnbridge
@@ -137,8 +137,8 @@ in
wantedBy = [ "network.target" ];
serviceConfig = {
Type = "forking";
ExecStart = "${cfg.dataDir}/vpnclient/vpnclient start";
ExecStop = "${cfg.dataDir}/vpnclient/vpnclient stop";
ExecStart = "${package}/bin/vpnclient start";
ExecStop = "${package}/bin/vpnclient stop";
};
preStart = ''
rm -rf ${cfg.dataDir}/vpnclient/vpnclient

View File

@@ -79,13 +79,13 @@ in
mkAttrsOfParams
{
version = mkIntParam 2 ''
version = mkIntParam 0 ''
IKE major version to use for connection.
- 1 uses IKEv1 aka ISAKMP,
- 2 uses IKEv2 (the default).
- A connection using 0 accepts both IKEv1 and IKEv2 as responder,
and initiates the connection actively with IKEv2.
- 2 uses IKEv2.
- A connection using the default of 0 accepts both IKEv1 and IKEv2 as
responder, and initiates the connection actively with IKEv2.
'';
local_addrs = mkCommaSepListParam [ ] ''

View File

@@ -149,28 +149,7 @@ in
"2270007"
];
description = ''
List of matchers specifying which rules should be disabled.
These can be raw SID numbers or something like "group:emerging-coinminer.rules".
'';
};
dropRules = mkOption {
type = types.listOf types.str;
default = [ ];
example = literalExpression ''
[ "2274852" "4327876" "902244405" ]
'';
description = ''
List of matchers specifying which rules should be converted to drop rules.
These can be raw SID numbers or something like "group:emerging-coinminer.rules".
'';
};
reloadOnRulesetUpdate = mkOption {
type = types.bool;
default = false;
description = ''
Whether to reload Suricata if it is running after an automated ruleset update.
This is a blocking reload, and may take some time depending on the number of rules and computational power of the host.
List of rules that should be disabled.
'';
};
};
@@ -234,20 +213,11 @@ in
};
systemd.services = {
suricata-blocking-reload = lib.mkIf cfg.reloadOnRulesetUpdate {
description = "Refresh Runtime Suricata Ruleset";
serviceConfig = {
Type = "oneshot";
ExecCondition = "systemctl is-active --quiet suricata.service";
ExecStart = "${pkg}/bin/suricatasc -c reload-rules";
};
};
suricata-update = {
description = "Update Suricata Rules";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
onSuccess = lib.mkIf cfg.reloadOnRulesetUpdate [ "suricata-blocking-reload.service" ];
script =
let
@@ -260,8 +230,7 @@ in
${concatStringsSep "\n" enabledSourcesCmds}
${python.interpreter} ${pkg}/bin/suricata-update update-sources
${python.interpreter} ${pkg}/bin/suricata-update update --suricata-conf ${cfg.configFile} --no-test \
--disable-conf ${pkgs.writeText "suricata-disable-conf" "${concatStringsSep "\n" cfg.disabledRules}"} \
--drop-conf ${pkgs.writeText "suricata-drop.conf" "${concatStringsSep "\n" cfg.dropRules}"}
--disable-conf ${pkgs.writeText "suricata-disable-conf" "${concatStringsSep "\n" cfg.disabledRules}"}
'';
serviceConfig = {
Type = "oneshot";

View File

@@ -11,7 +11,6 @@ with lib;
let
cfg = config.services.coder;
name = "coder";
configRefUrl = "https://coder.com/docs/@main/admin/setup/configuration-reference";
in
{
options = {
@@ -83,10 +82,7 @@ in
environment = {
extra = mkOption {
type = types.attrs;
description = ''
Extra environment variables to pass run Coder's server with.
See [Coder configuration reference](${configRefUrl}).
'';
description = "Extra environment variables to pass run Coder's server with. See Coder documentation.";
default = { };
example = {
CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS = true;
@@ -95,10 +91,7 @@ in
};
file = mkOption {
type = types.nullOr types.path;
description = ''
Systemd environment file to add to Coder.
See [Coder configuration reference](${configRefUrl}).
'';
description = "Systemd environment file to add to Coder.";
default = null;
};
};

View File

@@ -1,371 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.flame;
settingsFormat = pkgs.formats.json { };
# Accepts either a list of strings or a raw semicolon-separated string.
schemaToStr = x: if builtins.isList x then lib.concatStringsSep ";" x else x;
# Needed to prepopulate DB
sqlQuote = s: "'" + builtins.replaceStrings [ "'" ] [ "''" ] s + "'";
seedSql = pkgs.writeText "flame-seed.sql" ''
${lib.optionalString (cfg.apps != [ ] || cfg.categories != [ ]) ''
DELETE FROM bookmarks;
DELETE FROM categories;
DELETE FROM apps;
''}
${lib.concatMapStringsSep "\n" (app: ''
INSERT INTO apps (name, url, icon, description, isPinned, createdAt, updatedAt)
VALUES (${sqlQuote app.name}, ${sqlQuote app.url}, ${sqlQuote app.icon}, ${sqlQuote app.description}, ${
if app.isPinned then "1" else "0"
}, datetime('now'), datetime('now'));
'') cfg.apps}
${lib.concatMapStringsSep "\n" (cat: ''
INSERT INTO categories (name, isPinned, createdAt, updatedAt)
VALUES (${sqlQuote cat.name}, ${
if cat.isPinned then "1" else "0"
}, datetime('now'), datetime('now'));
${lib.concatMapStringsSep "\n" (bm: ''
INSERT INTO bookmarks (name, url, icon, categoryId, createdAt, updatedAt)
VALUES (${sqlQuote bm.name}, ${sqlQuote bm.url}, ${sqlQuote bm.icon}, (SELECT id FROM categories WHERE name = ${sqlQuote cat.name} ORDER BY id DESC LIMIT 1), datetime('now'), datetime('now'));
'') cat.bookmarks}
'') cfg.categories}
'';
cssFile = pkgs.writeText "flame-custom.css" cfg.customCSS;
# Build-time symlink farm of everything Flame ships except data/ and
# public/, which are left as empty placeholders here and populated at
# runtime (data/ is real state; public/ is refreshed from cfg.package
# on every start, since it holds built client assets).
appTree = pkgs.runCommand "flame-app-tree" { } ''
mkdir -p $out
for entry in ${cfg.package}/lib/flame/*; do
name=$(basename "$entry")
if [ "$name" != data ] && [ "$name" != public ]; then
ln -s "$entry" "$out/$name"
fi
done
mkdir -p $out/data $out/public
'';
# WEATHER_API_KEY is deliberately excluded here; it's injected at
# runtime from `weatherApiKeyFile` so it never touches the Nix store.
settingsFile = settingsFormat.generate "flame-settings.json" (
lib.filterAttrs (n: _: n != "weatherApiKeyFile") cfg.settings
// lib.optionalAttrs (cfg.settings ? greetingsSchema) {
greetingsSchema = schemaToStr cfg.settings.greetingsSchema;
}
// lib.optionalAttrs (cfg.settings ? daySchema) {
daySchema = schemaToStr cfg.settings.daySchema;
}
// lib.optionalAttrs (cfg.settings ? monthSchema) {
monthSchema = schemaToStr cfg.settings.monthSchema;
}
);
in
{
meta.maintainers = with lib.maintainers; [ DerGrumpf ];
options.services.flame = {
enable = lib.mkEnableOption "Flame, a self-hosted startpage for your server";
package = lib.mkPackageOption pkgs "flame" { };
port = lib.mkOption {
type = lib.types.port;
default = 5005;
description = "Port on which to serve the Flame web interface.";
};
passwordFile = lib.mkOption {
type = lib.types.path;
description = ''
Path to a file containing the password to log in to Flame's settings panel.
This is the recommended option as it avoids storing the password in the Nix store.
Compatible with sops-nix and agenix.
'';
example = "/run/secrets/flame-password";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the firewall for the port used by Flame.";
};
customCSS = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Custom CSS injected into Flame's UI, written to
{file}`public/flame.css` on every service start. Can also be used
to define a fully custom theme via CSS custom properties see
[Flame's Custom CSS wiki page](https://github.com/pawelmalak/flame/wiki/Custom-CSS).
'';
example = ''
.Home_SettingsButton__Qvn8C {
border-radius: 0 !important;
}
'';
};
categories = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
description = "Name of the bookmark category.";
};
isPinned = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether the category is pinned by default.";
};
bookmarks = lib.mkOption {
default = [ ];
description = "Bookmarks belonging to this category.";
type = lib.types.listOf (
lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
description = "Name of the bookmark.";
};
url = lib.mkOption {
type = lib.types.str;
description = "URL of the bookmark.";
};
icon = lib.mkOption {
type = lib.types.str;
default = "";
description = "Icon name or URL for the bookmark.";
};
};
}
);
};
};
}
);
default = [ ];
description = ''
Bookmark categories and their bookmarks. When non-empty, this
fully replaces the contents of Flame's `categories` and
`bookmarks` tables on every service start any bookmarks added
through the web UI will not persist across restarts.
'';
example = [
{
name = "Dev";
bookmarks = [
{
name = "GitHub";
url = "https://github.com";
}
];
}
];
};
apps = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
description = "Name of the app.";
};
url = lib.mkOption {
type = lib.types.str;
description = "URL of the app.";
};
icon = lib.mkOption {
type = lib.types.str;
default = "cancel";
description = "Icon name or URL for the app.";
};
description = lib.mkOption {
type = lib.types.str;
default = "";
description = "Short description shown for the app.";
};
isPinned = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether the app is pinned by default.";
};
};
}
);
default = [ ];
description = ''
Applications shown on the dashboard. When non-empty, this fully
replaces the contents of Flame's `apps` table on every service
start any apps added through the web UI will not persist
across restarts.
'';
example = [
{
name = "Router";
url = "http://192.168.1.1";
}
];
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
options = {
weatherApiKeyFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to a file containing the API key obtained from https://www.weatherapi.com used for
Flame's weather widget.
Compatible with sops-nix and agenix.
'';
example = "/run/secrets/flame-weather-api-key";
};
};
};
default = { };
description = ''
Flame settings, written to Flame's settings JSON on every service
start. Accepts any key Flame's settings API supports; see
[Flame's source](https://github.com/pawelmalak/flame/blob/master/client/src/context/context.js)
for the current schema, since Flame does not publish separate
settings documentation.
`greetingsSchema`, `daySchema`, and `monthSchema` accept either a
list of strings or a single semicolon-separated string.
'';
example = {
lat = 52.52;
long = 13.405;
customTitle = "My Dashboard";
hideHeader = true;
};
};
};
config = lib.mkIf cfg.enable {
systemd.services = {
flame-seed = lib.mkIf (cfg.apps != [ ] || cfg.categories != [ ]) {
description = "Seed Flame apps and bookmarks";
after = [ "flame.service" ];
requires = [ "flame.service" ];
wantedBy = [ "flame.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
DynamicUser = true;
StateDirectory = "flame";
};
script = ''
for i in $(seq 1 30); do
if ${lib.getExe pkgs.sqlite} /var/lib/flame/app/data/db.sqlite \
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='apps';" | grep -q 1; then
break
fi
sleep 1
done
${lib.getExe pkgs.sqlite} /var/lib/flame/app/data/db.sqlite < ${seedSql}
'';
};
flame = {
description = "Flame, a self-hosted startpage for your server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
preStart = ''
for entry in ${appTree}/*; do
name=$(basename "$entry")
if [ "$name" != data ] && [ "$name" != public ]; then
ln -sfn "$entry" /var/lib/flame/app/"$name"
fi
done
for entry in /var/lib/flame/app/data /var/lib/flame/app/public; do
if [ -L "$entry" ]; then
rm -f "$entry"
fi
done
mkdir -p /var/lib/flame/app/data/uploads /var/lib/flame/app/public
if [ ! -f /var/lib/flame/app/data/.secret ]; then
${lib.getExe pkgs.openssl} rand -hex 32 > /var/lib/flame/app/data/.secret
fi
chmod 644 /var/lib/flame/app/data/.secret
cp -r ${cfg.package}/lib/flame/public/. /var/lib/flame/app/public/
chmod -R u+w /var/lib/flame/app/public
install -m644 ${cssFile} /var/lib/flame/app/data/flame.css
${lib.getExe pkgs.jq} -n --slurpfile base ${cfg.package}/lib/flame/utils/init/initialConfig.json \
'$base[0]' > /var/lib/flame/app/data/config.json.tmp
${lib.optionalString (cfg.settings.weatherApiKeyFile != null) ''
weatherApiKey=$(cat ${cfg.settings.weatherApiKeyFile})
${lib.getExe pkgs.jq} --arg key "$weatherApiKey" '.WEATHER_API_KEY = $key' \
${settingsFile} > /var/lib/flame/app/data/settings-with-key.json
''}
${lib.getExe pkgs.jq} -s '.[0] * .[1]' \
/var/lib/flame/app/data/config.json.tmp \
${
if cfg.settings.weatherApiKeyFile != null then
"/var/lib/flame/app/data/settings-with-key.json"
else
settingsFile
} \
> /var/lib/flame/app/data/config.json
rm -f /var/lib/flame/app/data/config.json.tmp
chmod u+w /var/lib/flame/app/data/config.json
'';
serviceConfig = {
DynamicUser = true;
StateDirectory = [
"flame"
"flame/app"
];
WorkingDirectory = "/var/lib/flame/app";
Environment = [
"PORT=${toString cfg.port}"
"NODE_ENV=production"
"VERSION=${cfg.package.version}"
];
LoadCredential = [ "flame-password:${cfg.passwordFile}" ];
Restart = "always";
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
CapabilityBoundingSet = "";
};
script = ''
export PASSWORD="$(cat "$CREDENTIALS_DIRECTORY/flame-password")"
exec ${lib.getExe pkgs.nodejs} --preserve-symlinks --preserve-symlinks-main server.js
'';
};
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
};
}

View File

@@ -50,6 +50,9 @@ let
mkOption
mkEnableOption
;
postgresqlPackage =
if cfg.database.enable then config.services.postgresql.package else pkgs.postgresql;
in
{
imports = [
@@ -256,29 +259,6 @@ in
default = "immich";
description = "The database user for immich.";
};
package = mkOption {
type = types.package;
default =
if config.services.postgresql.enable then config.services.postgresql.package else pkgs.postgresql;
defaultText = lib.literalExpression ''
if config.services.postgresql.enable then
config.services.postgresql.package
else
pkgs.postgresql
'';
example = lib.literalExpression "pkgs.postgresql_18";
description = ''
The postgresql package providing the client programs that immich uses,
most notably the `pg_dumpall` of its database backup job.
These programs refuse to talk to a server that is newer than
themselves, so this must not be older than the server reachable at
{option}`services.immich.database.host`. It is derived from
{option}`services.postgresql.package` whenever the postgresql module
is enabled on this host; set it explicitly when the database lives on
another machine.
'';
};
};
redis = {
enable = mkEnableOption "a redis cache for use with immich" // {
@@ -357,7 +337,7 @@ in
in
[
''
${lib.getExe' cfg.database.package "psql"} -d "${cfg.database.name}" -f "${sqlFile}"
${lib.getExe' postgresqlPackage "psql"} -d "${cfg.database.name}" -f "${sqlFile}"
''
];
@@ -427,7 +407,7 @@ in
path = [
# gzip and pg_dumpall are used by the backup service
pkgs.gzip
cfg.database.package
postgresqlPackage
];
preStart = mkIf (cfg.settings != null) secretsReplacement.script;

View File

@@ -332,18 +332,6 @@ in
assertion = cfg.cron.enable -> cfg.cron.key != null;
message = ''services.invoiceplane.sites."${hostName}".cron.key must be set in order to use cron service.'';
}
{
assertion =
(lib.versionAtLeast (pkg hostName cfg).version "1.7.2" && cfg.invoiceTemplates != [ ])
-> cfg.settings ? CUSTOM_INVOICE_TEMPLATES_PDF;
message = ''services.invoiceplane.sites."${hostName}".invoiceTemplates is set but settings.CUSTOM_INVOICE_TEMPLATES_PDF is not. Since InvoicePlane >= 1.7.2 (current: ${cfg.package.version}), the filename of the custom invoice template PHP file must be explicitly whitelisted via settings.CUSTOM_INVOICE_TEMPLATES_PDF, otherwise it will not be picked up.'';
}
{
assertion =
(lib.versionAtLeast (pkg hostName cfg).version "1.7.2" && cfg.quoteTemplates != [ ])
-> cfg.settings ? CUSTOM_QUOTE_TEMPLATES_PDF;
message = ''services.invoiceplane.sites."${hostName}".quoteTemplates is set but settings.CUSTOM_QUOTE_TEMPLATES_PDF is not. Since InvoicePlane >= 1.7.2 (current: ${cfg.package.version}), the filename of the custom quote template PHP file must be explicitly whitelisted via settings.CUSTOM_QUOTE_TEMPLATES_PDF, otherwise it will not be picked up.'';
}
]) eachSite
);

View File

@@ -28,12 +28,12 @@ let
]}
}
'';
__structuredAttrs = true;
passAsFile = [ "serversList" ];
}
''
cp -r ${cfg.package}/assets $out
chmod +w "$out/servers_list.js"
printf "%s" "$serversList" > "$out/servers_list.js"
cp "$serversListPath" "$out/servers_list.js"
substitute ${cfg.package}/assets/index.html $out/index.html \
--replace-fail "s.setParameter(\"telemetry_level\",\"basic\"); //enable telemetry" "override_settings();" \
--replace-fail "LibreSpeed Example" ${lib.escapeShellArg (lib.escapeXML cfg.frontend.pageTitle)} \

View File

@@ -50,28 +50,10 @@ in
default = false;
description = ''
Disable HTTP token authentication with requests.
WARNING: This will make your instance vulnerable!
Only turn this on if nothing but trusted local clients can reach the API.
Note that web pages open in a browser on this machine also count as local
callers; restrict allowed_origins if you disable auth.
WARNING: This will make your instance vulnerable! Only turn this on if you are ONLY connecting from localhost.
'';
};
allowed_origins = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "*" ];
description = ''
Origins allowed to call the API from a browser.
This is a CORS allowlist, not an auth mechanism: it only governs which
web pages a browser will let read this API's responses.
The default "*" means any site open in your browser can send requests to
this instance, which matters most when disable_auth is on. Restrict this to
your own frontends to close that off, or use an empty list to block all
browser (cross-origin) callers.
'';
example = [ "http://localhost:8000" ];
};
disable_fetch_requests = lib.mkOption {
type = lib.types.bool;
default = false;
@@ -107,16 +89,6 @@ in
'';
example = 0;
};
access_log = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Log every HTTP request with client address, method, path and status.
Generation requests are already logged in detail; this adds the rest,
such as model list and health polls.
'';
};
};
logging = {
@@ -138,15 +110,6 @@ in
description = "Enable request logging. NOTE: Only use this for debugging!";
};
log_timestamps = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Prefix console log lines with the time of day.
The log files under logs/ always carry full timestamps.
'';
};
log_chat_completion_requests = lib.mkOption {
type = lib.types.bool;
default = false;
@@ -312,7 +275,7 @@ in
default = [ ];
description = ''
List of VRAM sizes to split between GPUs, in GB.
Used both with and without tensor parallelism.
Used with tensor parallelism.
'';
example = [
16
@@ -326,49 +289,10 @@ in
description = ''
Number of mixture-of-expert layers to offload to CPU inference.
Only affects MoE models. Set a large value such as 999 to offload all layers.
Mutually exclusive with cpu_moe_split_experts.
'';
example = 999;
};
cpu_moe_split_experts = lib.mkOption {
type = lib.types.ints.unsigned;
default = 0;
description = ''
Number of routed experts per MoE layer to offload to CPU inference.
Unlike cpu_moe_offload_layers, this splits every MoE layer instead of
offloading whole layers: the coldest experts are kept in system RAM and
computed on the CPU, overlapping each layer's own GPU compute, with dynamic
placement keeping hot experts in VRAM.
Mutually exclusive with cpu_moe_offload_layers; not supported with tensor
parallelism.
'';
example = 4;
};
cpu_moe_threads = lib.mkOption {
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
description = ''
Worker thread count for CPU MoE inference.
Applies to both cpu_moe_offload_layers and cpu_moe_split_experts. When null,
defers to the EXL3_MOE_CPU_THREADS environment variable, then half the CPU core
count.
'';
example = 8;
};
ngram_ram = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Load a model's n-gram embedding table fully into system RAM.
Only affects PLE models with n-gram embeddings (e.g. Qwen3.8-Flash-Next).
By default the table is streamed from disk during inference; loading it into
RAM avoids per-token disk reads at the cost of tens of GB of system memory.
'';
};
rope_scale = lib.mkOption {
type = lib.types.nullOr lib.types.number;
default = 1.0;
@@ -457,16 +381,6 @@ in
description = "Enables vision support if the model supports it.";
};
vision_offload = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Keep the vision model's weights in system RAM instead of VRAM.
Weights are stored in pinned host memory and streamed to the GPU during
inference, trading vision speed for VRAM. Only applies when vision is enabled.
'';
};
template_vars_default = lib.mkOption {
type = lib.types.attrsOf lib.types.anything;
default = { };
@@ -541,33 +455,6 @@ in
'';
};
reasoning_budget_tokens = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
description = ''
Default reasoning token budget.
When a request's reasoning content exceeds the budget, the server forces the
end of the reasoning phase by injecting reasoning_budget_message followed by
the model's end-of-reasoning tokens. 0 ends reasoning as soon as it starts;
null or a negative value disables the budget. Overridable per request via
reasoning_budget_tokens (aliases: reasoning_budget, thinking_budget,
thinking_token_budget) or reasoning.max_tokens.
Requires a reasoning format: reasoning tags, Harmony or Muse Glimmer.
'';
example = 1024;
};
reasoning_budget_message = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Text injected before the end-of-reasoning tokens when the reasoning budget is
exhausted. When null, only the end-of-reasoning tokens are forced.
Overridable per request via reasoning_budget_message.
'';
example = "Time to answer.";
};
tool_format = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
@@ -588,17 +475,6 @@ in
true. When active, supersedes the reasoning and tool format settings.
'';
};
muse_glimmer = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
default = null;
description = ''
Parse responses in the Muse Glimmer message format.
Auto-detected from the model's special tokens when null; set to true or false
to override. Setting tool_format to "muse_glimmer" is equivalent to setting
this to true. When active, supersedes the reasoning and tool format settings.
'';
};
};
draft_model = {
@@ -719,13 +595,10 @@ in
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Select a sampler override preset, found in the sampler_overrides folder of the
package.
Select a sampler override preset, found in the sampler-overrides folder.
This overrides default fallbacks for sampler values that are passed to the API.
NOTE: "safe_defaults" provides llama.cpp-style fallbacks (temperature 0.8,
top_k 40, top_p 0.95, min_p 0.05) for frontends that don't send sampling
parameters. Leaving this null means no fallbacks at all.
A preset that cannot be found makes TabbyAPI exit at startup.
NOTE: "safe_defaults" is noob friendly and provides fallbacks for frontends that
don't send sampling parameters. Leave this null for any advanced usage.
'';
example = "safe_defaults";
};
@@ -781,28 +654,14 @@ in
example = 4096;
};
sysmem_multimodal_cache = lib.mkOption {
type = lib.types.ints.unsigned;
default = 1024;
description = ''
Size of the image embedding cache in system memory, in MB.
Encoded images are kept so repeated turns of a conversation don't re-run the
vision model. Images already in use by a request are never evicted; a context
whose images exceed the budget is cached only partially, with a warning.
Only applies when vision is enabled.
'';
example = 4096;
};
cuda_malloc_async = lib.mkOption {
type = lib.types.bool;
default = false;
default = true;
description = ''
Use the cudaMallocAsync allocator backend in Torch.
When false, the allocator is left to the environment: unless
PYTORCH_CUDA_ALLOC_CONF is set, ExLlamaV3 enables expandable segments in
Torch's native allocator, which performs better than cudaMallocAsync.
Enable this to force the cudaMallocAsync backend instead.
Use the cudaMallocAsync backend in Torch.
Enabling this is generally preferable, but it may cause issues with certain
workloads. Try disabling it if you experience intermittent OoM errors. If false,
Torch will use the allocator defined by the system environment.
'';
};
};
@@ -830,14 +689,6 @@ in
services.tabbyapi.settings.model.template_vars_force.enable_thinking = true;
'';
}
{
assertion =
!(cfg.settings.model.cpu_moe_offload_layers > 0 && cfg.settings.model.cpu_moe_split_experts > 0);
message = ''
services.tabbyapi.settings.model.cpu_moe_offload_layers and
services.tabbyapi.settings.model.cpu_moe_split_experts are mutually exclusive.
'';
}
];
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [
cfg.settings.network.port
@@ -855,10 +706,6 @@ in
TRITON_CACHE_DIR = "/tmp/triton";
};
preStart = ''
ln -sfn ${cfg.package}/share/tabbyapi/sampler_overrides sampler_overrides
'';
serviceConfig = {
ExecStart = "${lib.getExe cfg.package} --config=${configFile}";
Restart = "on-failure";

View File

@@ -1,239 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.zerobyte;
in
{
meta.maintainers = with lib.maintainers; [ pbek ];
options.services.zerobyte = {
enable = lib.mkEnableOption "Zerobyte, backup automation for self-hosters built on top of restic";
package = lib.mkPackageOption pkgs "zerobyte" { };
user = lib.mkOption {
type = lib.types.str;
default = "zerobyte";
description = "User account under which Zerobyte runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = "zerobyte";
description = "Group under which Zerobyte runs.";
};
appSecretFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/run/secrets/zerobyte-app-secret";
description = ''
Path to a file containing the application secret (32256 characters),
used to encrypt sensitive data in the database. Generate one with
`openssl rand -hex 32`.
This should not be a path in the Nix store. The file is passed to the
service via systemd credentials.
'';
};
dataDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/zerobyte";
description = ''
Directory used to store the database, encryption keys, local
repositories, volume mounts and the restic cache.
Do not point this to a network share, this will cause permission
issues and strong performance degradation.
'';
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = lib.types.attrsOf (
lib.types.oneOf [
lib.types.bool
lib.types.int
lib.types.str
]
);
};
default = { };
example = {
BASE_URL = "https://zerobyte.example.com";
LOG_LEVEL = "debug";
GOMAXPROCS = 2;
TRUST_PROXY = true;
};
description = ''
Zerobyte configuration passed as environment variables. See
<https://github.com/nicotsx/zerobyte#configuration> for the available
settings.
`BASE_URL` is required. It is highly discouraged to expose Zerobyte
directly to the internet; bind `HOST` to localhost and use a secure
tunnel or an authenticating reverse proxy instead.
Do not put secrets here; use
[](#opt-services.zerobyte.environmentFile) instead.
'';
};
environmentFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/run/secrets/zerobyte.env";
description = ''
Environment file loaded by systemd, which may be used to pass secrets
such as `APP_SECRET` to Zerobyte without putting them into the Nix
store.
'';
};
provisioningFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to a JSON file with operator-managed repositories and volumes to
sync at startup. See
<https://zerobyte.app/docs/guides/provisioning> for the format.
This may contain secrets, so it should not be a path in the Nix store.
The file is passed to the service via systemd credentials.
'';
};
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = with pkgs; [
cifs-utils
davfs2
fuse3
nfs-utils
openssh
sshfs
util-linux
];
defaultText = lib.literalExpression "with pkgs; [ cifs-utils davfs2 fuse3 nfs-utils openssh sshfs util-linux ]";
description = ''
Extra packages added to the `PATH` of the Zerobyte service. The
default contains the tools needed to mount NFS, SMB, WebDAV and SFTP
volumes. Add `shoutrrr` here if you want notifications to be
delivered.
'';
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the firewall for the Zerobyte web interface.";
};
};
config = lib.mkIf cfg.enable {
services.zerobyte.settings = {
NODE_ENV = lib.mkDefault "production";
# The generated web server binds to all interfaces and port 3000 when
# these are unset. Bind to 127.0.0.1 and use port 4096 like upstream:
# https://github.com/nicotsx/zerobyte/blob/main/Dockerfile
HOST = lib.mkDefault "127.0.0.1";
PORT = lib.mkDefault 4096;
RESTIC_HOSTNAME = lib.mkDefault config.networking.hostName;
ZEROBYTE_DATABASE_URL = "${cfg.dataDir}/data/zerobyte.db";
RESTIC_PASS_FILE = "${cfg.dataDir}/data/restic.pass";
ZEROBYTE_REPOSITORIES_DIR = "${cfg.dataDir}/repositories";
ZEROBYTE_VOLUMES_DIR = "${cfg.dataDir}/volumes";
RESTIC_CACHE_DIR = "${cfg.dataDir}/restic/cache";
RCLONE_CONFIG_DIR = "${cfg.dataDir}/rclone";
ENABLE_LOCAL_AGENT = lib.mkDefault true;
}
// lib.optionalAttrs (cfg.provisioningFile != null) {
PROVISIONING_PATH = "%d/provisioning.json";
}
// lib.optionalAttrs (cfg.appSecretFile != null) {
APP_SECRET_FILE = "%d/app-secret";
};
assertions = [
{
assertion = cfg.settings ? BASE_URL;
message = "services.zerobyte.settings.BASE_URL must be set.";
}
{
assertion = cfg.appSecretFile != null || cfg.environmentFile != null || cfg.settings ? APP_SECRET;
message = ''
services.zerobyte: A secret is required to encrypt sensitive data in
the database. Set `services.zerobyte.appSecretFile` or provide
`APP_SECRET` via `services.zerobyte.environmentFile`.
'';
}
{
assertion = !(cfg.settings ? APP_SECRET);
message = ''
services.zerobyte.settings.APP_SECRET would expose the secret in the
Nix store. Use `services.zerobyte.appSecretFile` or
`services.zerobyte.environmentFile` instead.
'';
}
];
systemd.services.zerobyte = {
description = "Zerobyte backup automation";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = lib.mapAttrs (
_: value: if lib.isBool value then lib.boolToString value else toString value
) cfg.settings;
path = [ cfg.package ] ++ cfg.extraPackages;
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
ExecStart = lib.getExe cfg.package;
Restart = "on-failure";
StateDirectory = lib.mkIf (lib.hasPrefix "/var/lib/" cfg.dataDir) (
lib.removePrefix "/var/lib/" cfg.dataDir
);
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
LoadCredential =
lib.optional (cfg.appSecretFile != null) "app-secret:${cfg.appSecretFile}"
++ lib.optional (cfg.provisioningFile != null) "provisioning.json:${cfg.provisioningFile}";
# The local agent and the volume mount backends need these to perform
# NFS, SMB, WebDAV and SFTP mounts.
AmbientCapabilities = [ "CAP_SYS_ADMIN" ];
CapabilityBoundingSet = [ "CAP_SYS_ADMIN" ];
NoNewPrivileges = true;
PrivateTmp = true;
ProtectHome = lib.mkDefault false;
ProtectSystem = lib.mkDefault "full";
RestartSec = "10s";
UMask = "0077";
};
};
users.users = lib.mkIf (cfg.user == "zerobyte") {
zerobyte = {
isSystemUser = true;
group = cfg.group;
home = cfg.dataDir;
};
};
users.groups = lib.mkIf (cfg.group == "zerobyte") { zerobyte = { }; };
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ (lib.toInt (toString cfg.settings.PORT)) ];
};
};
}

View File

@@ -7,8 +7,6 @@
let
cfg = config.boot.initrd.nix-store-veritysetup;
json = pkgs.formats.json { };
in
{
meta.maintainers = with lib.maintainers; [ nikstur ];
@@ -29,15 +27,6 @@ in
contents = {
"/etc/systemd/system-generators/nix-store-veritysetup-generator".source =
"${lib.getExe pkgs.nix-store-veritysetup-generator}";
"/etc/systemd/generator-environment.json".source =
json.generate "systemd-generator-environment.json"
{
SYSTEMD_VERITYSETUP_PATH = "${config.boot.initrd.systemd.package}/lib/systemd/systemd-veritysetup";
};
"/etc/systemd/system-environment-generators/env-generator".source =
"${config.system.nixos-init.package}/bin/env-generator";
};
storePaths = [

View File

@@ -63,7 +63,6 @@ in
nixStoreMountOpts = mkOption {
type = types.listOf types.nonEmptyStr;
default = [
"x-initrd.mount"
"ro"
"nodev"
"nosuid"

View File

@@ -772,10 +772,7 @@ in
];
services.initrd-nixos-activation = lib.mkIf (!config.system.nixos-init.enable) {
after = [
"initrd-find-nixos-closure.service"
"initrd-switch-root.target"
];
after = [ "initrd-switch-root.target" ];
requiredBy = [ "initrd-switch-root.service" ];
before = [ "initrd-switch-root.service" ];
unitConfig.DefaultDependencies = false;

View File

@@ -15,12 +15,11 @@ let
mkIf
optionals
mkDefault
nameValuePair
listToAttrs
filterAttrs
mapAttrsToList
foldl'
getExe
escape
versionOlder
;
inInitrd = config.boot.initrd.supportedFilesystems.btrfs or false;
@@ -150,116 +149,66 @@ in
)
);
systemd.services."btrfs-scrub@" = {
description = "btrfs scrub on %f";
documentation = [ "man:btrfs-scrub(8)" ];
# scrub prevents suspend2ram or proper shutdown on linux < 6.19
conflicts = optionals (versionOlder config.boot.kernelPackages.kernel.version "6.19") [
"shutdown.target"
"sleep.target"
];
before = optionals (versionOlder config.boot.kernelPackages.kernel.version "6.19") [
"shutdown.target"
"sleep.target"
];
# TODO: Did not manage to do it via the usual btrfs-scrub@.timer/.service
# template units due to problems enabling the parameterized units,
# so settled with many units and templating via nix for now.
# https://github.com/NixOS/nixpkgs/pull/32496#discussion_r156527544
systemd.timers =
let
scrubTimer =
fs:
let
fs' = utils.escapeSystemdPath fs;
in
nameValuePair "btrfs-scrub-${fs'}" {
description = "regular btrfs scrub timer on ${fs}";
# prevent problems with MemoryDenyWriteExecute
environment.PYTHON_JIT = "0";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfgScrub.interval;
AccuracySec = "1d";
Persistent = true;
};
};
in
listToAttrs (map scrubTimer cfgScrub.fileSystems);
unitConfig.RequiresMountsFor = "%f";
systemd.services =
let
scrubService =
fs:
let
fs' = utils.escapeSystemdPath fs;
in
nameValuePair "btrfs-scrub-${fs'}" {
description = "btrfs scrub on ${fs}";
documentation = [ "man:btrfs-scrub(8)" ];
# scrub prevents suspend2ram or proper shutdown on linux < 6.19
conflicts = lib.optionals (lib.versionOlder config.boot.kernelPackages.kernel.version "6.19") [
"shutdown.target"
"sleep.target"
];
before = lib.optionals (lib.versionOlder config.boot.kernelPackages.kernel.version "6.19") [
"shutdown.target"
"sleep.target"
];
serviceConfig =
let
btrfsCmd = getExe pkgs.btrfs-progs;
btrfsCancelCmd = pkgs.writers.writePython3 "btrfs-scrub-maybe-cancel" { } ''
import subprocess
import sys
btrfs = "${escape [ "\"" "\\" ] btrfsCmd}"
result = subprocess.run(
[btrfs, "scrub", "cancel"] + sys.argv[1:],
stderr=subprocess.PIPE,
check=False,
shell=False
)
# ignore errors if there was no running scrub to cancel
if result.returncode == 2:
sys.exit(0)
sys.stderr.buffer.write(result.stderr)
sys.exit(result.returncode)
'';
additionalScrubArgs = optionals (cfgScrub.limit != null) [
"--limit"
cfgScrub.limit
];
in
{
# simple and not oneshot, otherwise ExecStop is not used
Type = "simple";
Nice = 19;
CPUSchedulingPolicy = "idle";
IOSchedulingClass = "idle";
ExecStart = "${
utils.escapeSystemdExecArgs (
[
btrfsCmd
"scrub"
"start"
"-B"
]
++ additionalScrubArgs
)
} %f";
# if the service is stopped before scrub end, cancel it
ExecStop = "${utils.escapeSystemdExecArg btrfsCancelCmd} %f";
# hardening
# required for starting/cancelling the scrub operation
CapabilityBoundingSet = [
"CAP_SYS_ADMIN"
"CAP_DAC_READ_SEARCH"
];
NoNewPrivileges = true;
# no ProtectSystem/ProtectHome since the path to be scrubbed can refer to a device,
# which in turn might be mounted there and mounting it read-only prevents scrubbing
StateDirectory = "btrfs"; # contains progress information
PrivateNetwork = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX" ]; # used internally for communication
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
SystemCallFilter = [
"@system-service"
"~@mount"
];
SystemCallArchitectures = "native";
# no ProtectKernelTunables since /sys/fs/btrfs access is required
# no User= since written files have to be accessible by scrub commands run manually
};
};
systemd.timers."btrfs-scrub@" = {
description = "Regular btrfs scrub on %f";
documentation = [ "man:btrfs-scrub(8)" ];
timerConfig = {
OnCalendar = cfgScrub.interval;
AccuracySec = "1d";
Persistent = true;
};
};
systemd.targets.timers.wants = map (
fs: "btrfs-scrub@${utils.escapeSystemdPath fs}.timer"
) cfgScrub.fileSystems;
serviceConfig = {
# simple and not oneshot, otherwise ExecStop is not used
Type = "simple";
Nice = 19;
IOSchedulingClass = "idle";
ExecStart = "${pkgs.btrfs-progs}/bin/btrfs scrub start -B ${
lib.optionalString (cfgScrub.limit != null) "--limit ${cfgScrub.limit}"
} ${fs}";
# if the service is stopped before scrub end, cancel it
ExecStop = pkgs.writeShellScript "btrfs-scrub-maybe-cancel" ''
(${pkgs.btrfs-progs}/bin/btrfs scrub status ${fs} | ${pkgs.gnugrep}/bin/grep finished) || ${pkgs.btrfs-progs}/bin/btrfs scrub cancel ${fs}
'';
};
};
in
listToAttrs (map scrubService cfgScrub.fileSystems);
})
];
}

View File

@@ -7,8 +7,6 @@
let
serialDevice = if pkgs.stdenv.hostPlatform.isx86 then "ttyS0" else "ttyAMA0";
efiArch = pkgs.stdenv.hostPlatform.efiArch;
in
{
meta = {
@@ -16,7 +14,6 @@ in
};
imports = [
../image/repart.nix
./lxc-instance-common.nix
../profiles/qemu-guest.nix
@@ -31,60 +28,6 @@ in
copyChannel = config.system.installer.channel.enable;
};
system.build.repartImage = config.image.repart.image.overrideAttrs (previousAttrs: {
nativeBuildInputs = previousAttrs.nativeBuildInputs ++ [ pkgs.qemu-utils ];
postBuild = ''
qemu-img convert -f raw -O qcow2 -c ${config.image.baseName}.raw ${config.image.baseName}.qcow2
rm ${config.image.baseName}.raw
'';
# expose a hydra build product so lxc-ci can download it
postInstall = ''
mkdir $out/nix-support
echo "file qcow2-image $out/${config.image.baseName}.qcow2" > $out/nix-support/hydra-build-products
'';
});
image.repart = {
name = "nixos";
version = null;
sectorSize = 512;
compression.enable = false;
mkfsOptions.ext4 = [
"-i"
"8192"
];
partitions = {
esp = {
contents = {
"/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source =
"${config.systemd.package}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
"/EFI/Linux/${config.system.boot.loader.ukiFile}".source =
"${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
};
repartConfig = {
Type = "esp";
Format = "vfat";
Label = "ESP";
# support 10 kernels, assuming 50MB on x86 and 100MB on aarch64
SizeMinBytes = if pkgs.stdenv.hostPlatform.isx86 then "512M" else "1G";
};
};
root = {
storePaths = [ config.system.build.toplevel ];
repartConfig = {
Type = "root";
Format = "ext4";
Label = "nixos";
Minimize = "guess";
PaddingMinBytes = "512M";
};
};
};
};
fileSystems = {
"/" = {
device = "/dev/disk/by-label/nixos";

View File

@@ -437,7 +437,7 @@ rec {
versionModule
./maintainers/scripts/incus/incus-virtual-machine-image.nix
];
}).config.system.build.repartImage
}).config.system.build.qemuImage
)
);

View File

@@ -93,47 +93,26 @@ in
};
};
testScript =
{ nodes, ... }:
let
orderRenewScript = nodes.client.systemd.services."acme-order-renew-${domain}".script;
in
''
${(import ./utils.nix).pythonUtils}
testScript = ''
${(import ./utils.nix).pythonUtils}
import shlex
cert = "${domain}"
cert = "${domain}"
dnsserver.start()
acme.start()
with subtest("Disable DNS propagation checks"):
order_renew_script = ${builtins.toJSON orderRenewScript}
lego_run_commands = [
line
for line in order_renew_script.splitlines()
if "lego run " in line
]
assert len(lego_run_commands) == 2, lego_run_commands
for command in lego_run_commands:
args = shlex.split(command)
assert "--dns.propagation.disable-ans" in args, args
assert "--dns.propagation.disable-rns" in args, args
assert "--dns.propagation.wait" not in args, args
wait_for_running(dnsserver)
dnsserver.wait_for_open_port(53)
wait_for_running(acme)
acme.wait_for_open_port(443)
dnsserver.start()
acme.start()
with subtest("Boot and acquire a new cert"):
client.start()
wait_for_running(client)
wait_for_running(dnsserver)
dnsserver.wait_for_open_port(53)
wait_for_running(acme)
acme.wait_for_open_port(443)
with subtest("Boot and acquire a new cert"):
client.start()
wait_for_running(client)
check_issuer(client, cert, "pebble")
check_domain(client, cert, cert, fail=True)
check_domain(client, cert, f"toodeep.nesting.{cert}", fail=True)
check_domain(client, cert, f"whatever.{cert}")
'';
check_issuer(client, cert, "pebble")
check_domain(client, cert, cert, fail=True)
check_domain(client, cert, f"toodeep.nesting.{cert}", fail=True)
check_domain(client, cert, f"whatever.{cert}")
'';
}

View File

@@ -6,31 +6,6 @@
let
domain = "example.test";
ip = "192.168.1.2";
migrationCertNames = [
"migration-2.${domain}"
"migration-3.${domain}"
];
migrationCerts = lib.genAttrs migrationCertNames (_: {
listenHTTP = ":80";
});
migrationTestLego = pkgs.writeShellScriptBin "lego" ''
if [[ ''${1-} == migrate ]]; then
printf '1\n' >> /run/acme/test-migration-attempts
if ! mkdir /run/acme/test-migration-active; then
touch /run/acme/test-migration-collision
exit 99
fi
trap 'rm -rf /run/acme/test-migration-active' EXIT
sleep 2
fi
${lib.getExe pkgs.lego} "$@"
'';
migrationServicePaths =
lib.genAttrs (map (name: "acme-order-renew-${name}") migrationCertNames)
(_: {
path = lib.mkBefore [ migrationTestLego ];
});
in
{
name = "http01-builtin";
@@ -63,12 +38,6 @@ in
listenHTTP = ":80";
};
# Delay account migration and fail a second concurrent invocation so
# the shared-account migration race is deterministic.
systemd.services."acme-order-renew-${config.networking.fqdn}".path = lib.mkBefore [
migrationTestLego
];
systemd.targets."renew-triggered" = {
wantedBy = [ "acme-order-renew-${config.networking.fqdn}.service" ];
after = [ "acme-order-renew-${config.networking.fqdn}.service" ];
@@ -112,18 +81,6 @@ in
preservation.configuration = { };
migration_serial.configuration = {
security.acme.maxConcurrentRenewals = 1;
security.acme.certs = migrationCerts;
systemd.services = migrationServicePaths;
};
migration_parallel.configuration = {
security.acme.maxConcurrentRenewals = 10;
security.acme.certs = migrationCerts;
systemd.services = migrationServicePaths;
};
add_cert_and_domain.configuration = {
security.acme.certs = {
"${config.networking.fqdn}" = {
@@ -139,10 +96,6 @@ in
security.acme.maxConcurrentRenewals = 10;
};
remove_domain.configuration = {
security.acme.certs."${config.networking.fqdn}".extraDomainNames = lib.mkForce [ ip ];
};
concurrency.configuration = {
# As above, relying on port binding behaviour to assert that concurrency limit
# prevents > 1 service running at a time.
@@ -217,12 +170,9 @@ in
domain = "${domain}"
ip = "${ip}"
jq = "${lib.getExe pkgs.jq}"
cert = "${certName}"
cert2 = "builtin-2." + domain
cert3 = "builtin-3." + domain
migration_certs = [cert] + ${builtins.toJSON migrationCertNames}
migration_units = [f"acme-order-renew-{name}.service" for name in migration_certs]
legacy_account_dir = "/var/lib/acme/.lego/accounts/1ccf607d9aa280e9af00"
acme.start()
@@ -237,93 +187,6 @@ in
check_domain(builtin, cert, cert)
check_ip(builtin, cert, ip)
with subtest("Handles v4 account and certificate state"):
switch_to(builtin, "migration_serial")
for migration_cert in migration_certs:
check_issuer(builtin, migration_cert, "pebble")
check_domain(builtin, migration_cert, migration_cert)
switch_to(builtin, "migration_parallel")
builtin.succeed(f"systemctl start {' '.join(migration_units)}")
builtin.succeed(
f"""
set -euo pipefail
account_file=$(find /var/lib/acme/.lego/accounts -type f -name account.json -print -quit)
test -n "$account_file"
account_dir=$(dirname "$account_file")
account_id=$(basename "$account_dir")
key_path="$account_dir/$account_id.key"
test -f "$key_path"
mkdir "$account_dir/keys"
mv "$key_path" "$account_dir/keys/$account_id.key"
{jq} '{{
email: .email,
registration: {{
body: (.registration | del(.accountURL)),
uri: .registration.accountURL
}}
}}' "$account_dir/account.json" > "$account_dir/account.json.tmp"
mv "$account_dir/account.json.tmp" "$account_dir/account.json"
{jq} -e '
.registration.body.status == "valid"
and (.registration.uri | startswith("https://acme.test/"))
' "$account_dir/account.json" > /dev/stderr
cert_resource=$(find "/var/lib/acme/.lego/{cert}" -type f -name '{cert}.json' -print -quit)
test -n "$cert_resource"
{jq} '{{
domain: .id,
certUrl: .certUrl,
certStableUrl: .certStableUrl
}}' "$cert_resource" > "$cert_resource.tmp"
mv "$cert_resource.tmp" "$cert_resource"
chown -R acme:acme /var/lib/acme/.lego/accounts "/var/lib/acme/.lego/{cert}"
chmod -R u=rwX,g=,o= /var/lib/acme/.lego/accounts
chmod -R u=rwX,g=rX,o= "/var/lib/acme/.lego/{cert}"
rm -rf /run/acme/test-migration-*
"""
)
builtin.succeed(f"systemctl start {' '.join(migration_units)}")
builtin.succeed('test "$(wc -l < /run/acme/test-migration-attempts)" -eq 1')
builtin.succeed("test ! -e /run/acme/test-migration-active")
builtin.succeed("test ! -e /run/acme/test-migration-collision")
builtin.succeed(
f"""
set -euo pipefail
account_file=$(find /var/lib/acme/.lego/accounts -type f -name account.json -print -quit)
test -n "$account_file"
account_dir=$(dirname "$account_file")
account_id=$(basename "$account_dir")
test -f "$account_dir/$account_id.key"
test ! -e "$account_dir/keys"
{jq} -e '
.origin == "migration"
and .keyType == "EC256"
and .server == "https://acme.test/dir"
and .registration.status == "valid"
and (.registration.accountURL | startswith("https://acme.test/"))
' "$account_dir/account.json" > /dev/stderr
"""
)
builtin.succeed(f"systemctl start acme-order-renew-{cert}.service")
check_issuer(builtin, cert, "pebble")
check_domain(builtin, cert, cert)
check_ip(builtin, cert, ip)
for migration_cert in migration_certs[1:]:
check_issuer(builtin, migration_cert, "pebble")
check_domain(builtin, migration_cert, migration_cert)
with subtest("Validate permissions"):
check_permissions(builtin, cert, "acme")
@@ -435,16 +298,6 @@ in
check_permissions(builtin, cert, "acme")
check_permissions(builtin, cert2, "acme")
with subtest("Remove an existing cert domain"):
builtin.succeed("systemctl stop renew-triggered.target")
switch_to(builtin, "remove_domain")
builtin.wait_for_unit("renew-triggered.target")
check_issuer(builtin, cert, "pebble")
check_domain(builtin, cert, f"builtin-alt.{domain}", fail=True)
check_ip(builtin, cert, ip)
check_permissions(builtin, cert, "acme")
with subtest("Check account hashing compatibility with pre-24.05 settings"):
builtin.succeed("systemctl stop renew-triggered.target")
switch_to(builtin, "legacy_account_hash"

View File

@@ -15,8 +15,7 @@
# Example callTest that just extracts the derivation from the test:
# callTest = t: t.test;
let
inherit (pkgs) lib;
inherit (lib)
inherit (pkgs.lib)
isAttrs
isFunction
mapAttrs
@@ -99,25 +98,13 @@ let
featureFlags.minimalModules = { };
};
evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; };
/**
On platforms where NixOS does not run natively, nixosTests is still available
as a convenience for running VM tests. This makes them easier to use, and it
sidesteps the question of nested virtualisation.
`runTest` already includes similar logic as part of its [public] interface.
[public]: https://nixos.org/manual/nixos/stable/#sec-call-nixos-test-outside-nixos
*/
inherit (pkgs) pkgsLinux;
evalSystem =
module:
import ../lib/eval-config.nix {
system = null;
modules = [
../modules/misc/nixpkgs/read-only.nix
{ nixpkgs.pkgs = pkgsLinux; }
{ nixpkgs.pkgs = pkgs; }
module
];
};
@@ -236,7 +223,8 @@ in
accountsservice = runTest ./accountsservice.nix;
acl = pkgs.callPackage ./acl.nix { };
acme = import ./acme/default.nix {
inherit runTest lib;
inherit runTest;
inherit (pkgs) lib;
};
acme-dns = runTest ./acme-dns.nix;
activation = pkgs.callPackage ../modules/system/activation/test.nix { };
@@ -301,7 +289,6 @@ in
audiobookshelf = runTest ./audiobookshelf.nix;
audit = runTest ./audit.nix;
audit-testsuite = runTest ./audit-testsuite.nix;
aurral = runTest ./aurral.nix;
auth-mysql = runTest ./auth-mysql.nix;
authelia = runTest ./authelia.nix;
auto-cpufreq = runTest ./auto-cpufreq.nix;
@@ -375,7 +362,6 @@ in
btrbk-doas = runTest ./btrbk-doas.nix;
btrbk-no-timer = runTest ./btrbk-no-timer.nix;
btrbk-section-order = runTest ./btrbk-section-order.nix;
btrfs-autoscrub = runTest ./btrfs-autoscrub.nix;
budgie = runTest ./budgie.nix;
buildbot = runTest ./buildbot.nix;
buildkite-agents = runTest ./buildkite-agents.nix;
@@ -439,13 +425,12 @@ in
inherit runTest;
package = pkgs.clickhouse-lts;
};
cliproxyapi = runTest ./cliproxyapi.nix;
cloud-init = runTest ./cloud-init.nix;
cloud-init-hostname = runTest ./cloud-init-hostname.nix;
cloudcompare = import ./cloudcompare.nix { inherit pkgs runTest; };
cloudlog = runTest ./cloudlog.nix;
cntr = import ./cntr.nix {
inherit lib;
inherit (pkgs) lib;
runTest = runTestOn [
"aarch64-linux"
"x86_64-linux"
@@ -624,15 +609,18 @@ in
ergochat = runTest ./ergochat.nix;
ersatztv = runTest ./ersatztv.nix;
espanso = import ./espanso.nix {
inherit lib runTest;
inherit (pkgs) lib;
inherit runTest;
};
esphome = runTest ./esphome.nix;
etc = pkgsLinux.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; };
etc = pkgs.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; };
etcd = import ./etcd/default.nix { inherit pkgs runTest; };
etebase-server = runTest ./etebase-server.nix;
etesync-dav = runTest ./etesync-dav.nix;
evcc = runTest ./evcc.nix;
extra-initrd = import ./extra-initrd.nix { inherit runTest; };
extra-initrd = import ./extra-initrd.nix {
inherit runTest pkgs;
};
facter = runTest ./facter;
fail2ban = runTest ./fail2ban.nix;
fakeroute = runTest ./fakeroute.nix;
@@ -693,7 +681,6 @@ in
firewalld = runTest ./firewalld.nix;
firezone = runTest ./firezone/firezone.nix;
fish = runTest ./fish.nix;
flame = runTest ./flame.nix;
flannel = runTestOn [ "x86_64-linux" ] ./flannel.nix;
flap-alerted = runTest ./flap-alerted.nix;
flaresolverr = runTest ./flaresolverr.nix;
@@ -706,12 +693,13 @@ in
fontconfig-default-fonts = runTest ./fontconfig-default-fonts.nix;
forgejo = import ./forgejo.nix {
inherit runTest;
forgejoPackage = pkgsLinux.forgejo;
forgejoPackage = pkgs.forgejo;
};
forgejo-lts = import ./forgejo.nix {
inherit runTest;
forgejoPackage = pkgsLinux.forgejo-lts;
forgejoPackage = pkgs.forgejo-lts;
};
freenet = runTest ./freenet.nix;
freescout = import ./freescout {
inherit runTest;
};
@@ -736,11 +724,11 @@ in
gancio = runTest ./gancio.nix;
garage_1 = import ./garage {
inherit runTest;
package = pkgsLinux.garage_1;
package = pkgs.garage_1;
};
garage_2 = import ./garage {
inherit runTest;
package = pkgsLinux.garage_2;
package = pkgs.garage_2;
};
gatus = runTest ./gatus.nix;
gemstash = import ./gemstash.nix { inherit pkgs runTest; };
@@ -754,9 +742,8 @@ in
git-pages-modular = runTest ./git-pages.nix;
gitdaemon = runTest ./gitdaemon.nix;
gitea = import ./gitea.nix {
inherit (pkgsLinux) gitea;
inherit runTest;
inherit lib;
inherit pkgs runTest;
inherit (pkgs) lib;
};
gitea-actions-runner = runTest ./gitea-actions-runner.nix;
github-runner = runTest ./github-runner.nix;
@@ -793,9 +780,7 @@ in
gotify-server = runTest ./gotify-server.nix;
gotosocial = runTest ./web-apps/gotosocial.nix;
goupile = runTest ./web-apps/goupile;
grafana = import ./grafana {
inherit runTest;
};
grafana = handleTest ./grafana { };
grafana-to-ntfy = runTest ./grafana-to-ntfy.nix;
graphite = runTest ./graphite.nix;
grav = runTest ./web-apps/grav.nix;
@@ -815,7 +800,8 @@ in
guix = handleTest ./guix { };
gvisor = runTest ./gvisor.nix;
h2o = import ./web-servers/h2o {
inherit lib runTest;
inherit runTest;
inherit (pkgs) lib;
};
hadoop = import ./hadoop {
inherit handleTestOn;
@@ -861,7 +847,6 @@ in
hibernate-systemd-stage-1 = handleTestOn [ "x86_64-linux" ] ./hibernate.nix {
systemdStage1 = true;
};
hickory-dns = runTest ./hickory-dns.nix;
hister = runTest ./hister.nix;
hitch = runTest ./hitch;
hledger-web = runTest ./hledger-web.nix;
@@ -881,7 +866,6 @@ in
hound = runTest ./hound.nix;
hub = runTest ./git/hub.nix;
hydra = runTest ./hydra;
hyphanet = runTest ./hyphanet.nix;
i18n = runTest ./i18n.nix;
i2pd = runTest ./i2pd.nix;
i3wm = runTest ./i3wm.nix;
@@ -927,7 +911,6 @@ in
inventree = runTest ./inventree.nix;
invidious = runTest ./invidious.nix;
invoiceplane = runTest ./invoiceplane.nix;
iocaine = runTest ./iocaine.nix;
iodine = runTest ./iodine.nix;
iosched = runTest ./iosched.nix;
ipget = runTest ./ipget.nix;
@@ -944,22 +927,18 @@ in
jibri = runTest ./jibri.nix;
jirafeau = runTest ./jirafeau.nix;
jitsi-meet = runTest ./jitsi-meet.nix;
jool = import ./jool.nix {
pkgs = pkgsLinux;
inherit runTest;
};
jool = import ./jool.nix { inherit pkgs runTest; };
jotta-cli = runTest ./jotta-cli.nix;
k3s = import ./rancher {
inherit lib pkgs;
inherit pkgs;
inherit (pkgs) lib;
runTest = runTestOn [
"aarch64-linux"
"x86_64-linux"
];
rancherDistro = "k3s";
};
kafka = import ./kafka {
inherit runTest pkgs;
};
kafka = handleTest ./kafka { };
kaidan = runTest ./kaidan;
kanboard = runTest ./web-apps/kanboard.nix;
kanidm = runTest ./kanidm.nix;
@@ -974,9 +953,7 @@ in
keepalived = discoverTests (import ./keepalived.nix);
keepassxc = runTest ./keepassxc.nix;
kener = runTest ./kener.nix;
kerberos = import ./kerberos/default.nix {
inherit pkgs runTest;
};
kerberos = handleTest ./kerberos/default.nix { };
kernel-generic = handleTest ./kernel-generic { };
kernel-latest-ath-user-regd = runTest ./kernel-latest-ath-user-regd.nix;
kernel-rust = handleTest ./kernel-rust.nix { };
@@ -1006,7 +983,8 @@ in
kthxbye = runTest ./kthxbye.nix;
kubernetes = handleTestOn [ "x86_64-linux" ] ./kubernetes { };
kubo = import ./kubo {
inherit lib runTest;
inherit runTest;
inherit (pkgs) lib;
};
kvrocks = runTest ./kvrocks.nix;
labgrid = runTest ./labgrid.nix;
@@ -1115,7 +1093,7 @@ in
matrix-tuwunel = runTest ./matrix/tuwunel.nix;
matter-server = runTest ./matter-server.nix;
matterjs-server = runTest ./matterjs-server.nix;
mattermost = runTest ./mattermost;
mattermost = handleTest ./mattermost { };
mautrix-discord = runTest ./matrix/mautrix-discord.nix;
mautrix-meta-postgres = runTest ./matrix/mautrix-meta-postgres.nix;
mautrix-meta-sqlite = runTest ./matrix/mautrix-meta-sqlite.nix;
@@ -1123,7 +1101,8 @@ in
mediamtx = runTest ./mediamtx.nix;
mediatomb = runTest ./mediatomb.nix;
mediawiki = import ./mediawiki.nix {
inherit lib runTest;
inherit (pkgs) lib;
inherit runTest;
};
meilisearch = runTest ./meilisearch.nix;
memcached = runTest ./memcached.nix;
@@ -1146,7 +1125,7 @@ in
mobilizon = runTest ./mobilizon.nix;
mod_perl = runTest ./mod_perl.nix;
modular-service-etc = runTest ./modular-service-etc/test.nix;
modularService = pkgsLinux.callPackage ../modules/system/service/systemd/test.nix {
modularService = pkgs.callPackage ../modules/system/service/systemd/test.nix {
inherit evalSystem;
};
moduleStateRevisions = pkgs.callPackage ./moduleStateRevisions.nix { };
@@ -1177,7 +1156,8 @@ in
morph-browser = discoverTests (import ./morph-browser.nix);
mosquitto = runTest ./mosquitto.nix;
movim = import ./web-apps/movim {
inherit lib runTest;
inherit runTest;
inherit (pkgs) lib;
};
mpd = runTest ./mpd.nix;
mpv = runTest ./mpv.nix;
@@ -1278,7 +1258,7 @@ in
nginx-status-page = runTest ./nginx-status-page.nix;
nginx-tmpdir = runTest ./nginx-tmpdir.nix;
nginx-unix-socket = runTest ./nginx-unix-socket.nix;
nginx-variants = import ./nginx-variants.nix { inherit runTest; };
nginx-variants = import ./nginx-variants.nix { inherit pkgs runTest; };
nifi = runTestOn [ "x86_64-linux" ] ./web-apps/nifi.nix;
nimdow = runTest ./nimdow.nix;
nipap = runTest ./web-apps/nipap.nix;
@@ -1382,7 +1362,6 @@ in
ollama-cuda = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./ollama-cuda.nix;
ollama-rocm = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./ollama-rocm.nix;
ollama-vulkan = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./ollama-vulkan.nix;
omada = runTestOn [ "x86_64-linux" ] ./omada.nix;
ombi = runTest ./ombi.nix;
omnom = runTest ./omnom;
oncall = runTest ./web-apps/oncall.nix;
@@ -1449,7 +1428,8 @@ in
patroni = handleTestOn [ "x86_64-linux" ] ./patroni.nix { };
pcsclite = runTest ./pcsclite.nix;
pdfding = import ./web-apps/pdfding {
inherit lib runTest;
inherit (pkgs) lib;
inherit runTest;
};
pdns-recursor = runTest ./pdns-recursor.nix;
pdudaemon = runTest ./pdudaemon.nix;
@@ -1517,10 +1497,7 @@ in
{ };
postfix-tlspol = runTest ./postfix-tlspol.nix;
postgres-websockets = runTest ./postgres-websockets.nix;
postgresql = import ./postgresql {
inherit runTest;
pkgs = pkgsLinux;
};
postgresql = import ./postgresql { inherit runTest pkgs; };
postgrest = runTest ./postgrest.nix;
power-profiles-daemon = runTest ./power-profiles-daemon.nix;
powerdns = runTest ./powerdns.nix;
@@ -1558,7 +1535,8 @@ in
privoxy = runTest ./privoxy.nix;
prometheus = import ./prometheus { inherit runTest; };
prometheus-exporters = import ./prometheus-exporters.nix {
inherit lib runTest;
inherit runTest;
inherit (pkgs) lib;
};
prosody = runTest ./xmpp/prosody.nix;
prosody-mysql = handleTest ./xmpp/prosody-mysql.nix { };
@@ -1598,16 +1576,14 @@ in
rathole = runTest ./rathole.nix;
rauc = runTest ./rauc.nix;
reaction = import ./reaction {
inherit lib runTest;
inherit (pkgs) lib;
inherit runTest;
};
readarr = runTest ./readarr.nix;
readeck = runTest ./readeck.nix;
realm = runTest ./realm.nix;
rebuilderd = runTest ./rebuilderd.nix;
redis = runTest {
imports = [ ./redis.nix ];
_module.args.package = pkgs.redis;
};
redis = handleTest ./redis.nix { };
redlib = runTest ./redlib.nix;
redmine = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./redmine.nix { };
refind = runTest ./refind.nix;
@@ -1622,7 +1598,8 @@ in
retroarch = runTest ./retroarch.nix;
ringboard = runTest ./ringboard.nix;
rke2 = import ./rancher {
inherit lib pkgs;
inherit pkgs;
inherit (pkgs) lib;
runTest = runTestOn [
"aarch64-linux"
"x86_64-linux"
@@ -1750,7 +1727,8 @@ in
sunshine = runTest ./sunshine.nix;
suricata = runTest ./suricata.nix;
suwayomi-server = import ./suwayomi-server.nix {
inherit lib runTest;
inherit runTest;
inherit (pkgs) lib;
};
svnserve = runTest ./svnserve.nix;
swap-file-btrfs = runTest ./swap-file-btrfs.nix;
@@ -1791,18 +1769,19 @@ in
system-services-compliance = recurseIntoAttrs (
import ./system-services-compliance.nix {
inherit
pkgs
evalSystem
runTest
callTest
;
pkgs = pkgsLinux;
}
);
systemd = runTest ./systemd.nix;
systemd-analyze = runTest ./systemd-analyze.nix;
systemd-binfmt = handleTestOn [ "x86_64-linux" ] ./systemd-binfmt.nix { };
systemd-boot = import ./systemd-boot.nix {
inherit lib runTest runTestOn;
inherit runTest runTestOn;
inherit (pkgs) lib;
};
systemd-bpf = runTest ./systemd-bpf.nix;
systemd-capsules = runTest ./systemd-capsules.nix;
@@ -1986,13 +1965,9 @@ in
utmp = runTest ./utmp.nix;
uwsgi = runTest ./uwsgi.nix;
v2ray = runTest ./v2ray.nix;
valkey = runTest {
imports = [ ./redis.nix ];
_module.args.package = pkgs.valkey;
};
varnish80 = runTest {
imports = [ ./varnish.nix ];
_module.args.package = pkgsLinux.varnish80;
_module.args.package = pkgs.varnish80;
};
vault = runTest ./vault.nix;
vault-agent = runTest ./vault-agent.nix;
@@ -2010,7 +1985,7 @@ in
vikunja = runTest ./vikunja.nix;
vinyl-cache_9 = runTest {
imports = [ ./vinyl-cache.nix ];
_module.args.package = pkgsLinux.vinyl-cache_9;
_module.args.package = pkgs.vinyl-cache_9;
};
virtualbox = handleTestOn [ "x86_64-linux" ] ./virtualbox.nix { };
vm-variant = handleTest ./vm-variant.nix { };
@@ -2035,15 +2010,16 @@ in
whoogle-search = runTest ./whoogle-search.nix;
wiki-js = runTest ./wiki-js.nix;
windmill = import ./windmill {
inherit runTest;
inherit pkgs runTest;
inherit (pkgs) lib;
};
wine = import ./wine.nix {
inherit pkgs runTest;
inherit (pkgs) lib;
};
wireguard = import ./wireguard {
pkgs = pkgsLinux;
inherit runTest lib;
inherit pkgs runTest;
inherit (pkgs) lib;
};
without-nix = runTest ./without-nix.nix;
wmderland = runTest ./wmderland.nix;
@@ -2051,7 +2027,7 @@ in
workout-tracker = runTest ./workout-tracker.nix;
wpa_supplicant = import ./wpa_supplicant.nix { inherit pkgs runTest; };
wrappers = runTest ./wrappers.nix;
writefreely = import ./web-apps/writefreely.nix { inherit runTest; };
writefreely = import ./web-apps/writefreely.nix { inherit pkgs runTest; };
wstunnel = runTest ./wstunnel.nix;
xandikos = runTest ./xandikos.nix;
xautolock = runTest ./xautolock.nix;
@@ -2069,14 +2045,14 @@ in
yarr = runTest ./yarr.nix;
yb = pkgs.callPackage ./yb.nix { inherit (pkgs.yb.passthru) ybPivHarnessTests testFixtures; };
ydotool = import ./ydotool.nix {
inherit lib runTest;
inherit (pkgs) lib;
inherit runTest;
};
yggdrasil = runTest ./yggdrasil.nix;
your_spotify = runTest ./your_spotify.nix;
zammad = runTest ./zammad.nix;
zapret2 = runTest ./zapret2.nix;
zenohd = runTest ./zenohd.nix;
zerobyte = runTest ./zerobyte.nix;
zeronet-conservancy = runTest ./zeronet-conservancy.nix;
zfs = import ./zfs.nix { inherit system pkgs runTest; };
zigbee2mqtt = runTest ./zigbee2mqtt.nix;

View File

@@ -27,8 +27,6 @@
};
image.repart = {
enable = true;
verityStore = {
enable = true;
# by default the module works with systemd-boot, for simplicity this test directly boots the UKI

View File

@@ -46,8 +46,6 @@ in
};
image.repart = {
enable = true;
name = "appliance-gpt-image";
# OVMF does not work with the default repart sector size of 4096
sectorSize = 512;

View File

@@ -1,29 +0,0 @@
{ lib, ... }:
{
name = "aurral";
meta = with lib.maintainers; {
maintainers = [ hougo ];
};
nodes = {
machine =
{ ... }:
{
services.aurral = {
enable = true;
environment = {
DOWNLOAD_FOLDER = "/var/lib/aurral-downloads";
};
};
};
};
testScript = ''
start_all()
machine.wait_for_unit("aurral.service")
machine.wait_for_open_port(3001)
machine.succeed('curl --fail http://localhost:3001/api/health')
'';
}

View File

@@ -1,69 +0,0 @@
{ ... }:
{
name = "btrfs-autoscrub";
nodes.machine =
{ ... }:
{
virtualisation.emptyDiskImages = [ 128 ];
# test sandbox permissiveness and command line escaping
virtualisation.fileSystems."/home/test/btrfs autoscrub test" = {
fsType = "btrfs";
device = "/dev/vdb";
autoFormat = true;
options = [ "X-mount.mkdir" ];
};
services.btrfs.autoScrub = {
enable = true;
# test that setting the limit works
limit = "1G";
};
};
testScript = ''
def run_scrub(fs):
machine.start_job(f"'btrfs-scrub@{fs}.service'")
machine.wait_until_fails(f"systemctl --quiet is-active 'btrfs-scrub@{fs}.service'")
machine.fail(f"systemctl is-failed 'btrfs-scrub@{fs}.service'")
invocation_id = machine.succeed(
f"systemctl show --value -p InvocationID 'btrfs-scrub@{fs}.service'"
)
output = machine.succeed(
f"journalctl --no-pager _SYSTEMD_INVOCATION_ID={invocation_id}"
)
t.assertNotRegex(output, "(?i)warning:|error:")
start_all()
machine.wait_for_unit("multi-user.target")
fs = "/home/test/btrfs autoscrub test"
escaped = r"home-test-btrfs\x20autoscrub\x20test"
with subtest("Verify that the configured timers and file systems are active"):
machine.require_unit_state(f"{escaped}.mount", "active")
machine.require_unit_state(f"btrfs-scrub@{escaped}.timer", "active")
# disable timers (and possible triggered services) to prevent them
# from interfering with the tests
machine.stop_job(f"'btrfs-scrub@{escaped}.timer'")
machine.stop_job(f"'btrfs-scrub@{escaped}.service'")
with subtest("Verify that scrubbing works"):
run_scrub(escaped)
result = machine.succeed(f"btrfs scrub status '{fs}'")
t.assertRegex(result, r"Status:\s*finished")
with subtest("Verify that scrubbing causes filesystems to be mounted"):
machine.stop_job(f"'{escaped}.mount'")
run_scrub(escaped)
machine.require_unit_state(f"{escaped}.mount", "active")
with subtest("Verify that the service can scrub private mountpoints"):
machine.succeed(f"chmod 000 '{fs}'")
machine.succeed("chmod 000 /home/test")
run_scrub(escaped)
with subtest("Verify that the service can scrub device files directly"):
run_scrub("dev-vdb")
'';
}

View File

@@ -1,6 +1,7 @@
{
pkgs,
runTest,
...
}:
let

View File

@@ -1,4 +1,4 @@
{ runTest, pkgs }:
{ runTest, pkgs, ... }:
let
authKey = pkgs.writeText "auth-key" "1234ABCD";

View File

@@ -1,41 +0,0 @@
{ lib, ... }:
{
name = "cliproxyapi";
meta.maintainers = [ lib.maintainers.anish ];
containers.machine =
{ pkgs, ... }:
{
services.cliproxyapi = {
enable = true;
settings = {
host = "127.0.0.1";
port = 8317;
api-keys = [ { _secret = "/etc/cliproxyapi-api-key"; } ];
};
};
environment.etc."cliproxyapi-api-key".text = "test-key";
environment.systemPackages = [ pkgs.curl ];
};
testScript = ''
machine.wait_for_unit("cliproxyapi.service")
machine.wait_for_open_port(8317)
# The API key secret must be substituted into config.yaml.
machine.succeed("grep -q test-key /var/lib/cliproxyapi/config.yaml")
# Requests without a valid API key are rejected.
status = machine.succeed(
"curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8317/v1/models"
).strip()
assert status == "401", f"expected 401 for unauthenticated /v1/models, got {status}"
# Requests carrying the configured API key are accepted.
machine.succeed(
"curl -sf -H 'Authorization: Bearer test-key' http://127.0.0.1:8317/v1/models"
)
'';
}

View File

@@ -1,6 +1,7 @@
{
pkgs,
runTest,
...
}:
let

View File

@@ -1,4 +1,7 @@
{ runTest }:
{
runTest,
...
}:
let
common =
{ config, pkgs, ... }:

View File

@@ -1,68 +0,0 @@
{ lib, ... }:
{
name = "flame";
meta.maintainers = with lib.maintainers; [ DerGrumpf ];
nodes.machine = {
services.flame = {
enable = true;
passwordFile = "/etc/flame-password";
apps = [
{
name = "Test App";
url = "http://example.com";
}
];
categories = [
{
name = "Test Category";
bookmarks = [
{
name = "Nixpkgs";
url = "https://github.com/NixOS/nixpkgs";
}
];
}
];
settings = {
customTitle = "Test Flame";
customUnknownKey = "test-value";
};
customCSS = ''
body { background: #123456; }
'';
};
systemd.tmpfiles.rules = [
"f /etc/flame-password 0400 root root - testpassword"
];
};
testScript = ''
machine.wait_for_unit("flame.service")
machine.wait_for_open_port(5005)
machine.succeed("curl -f http://localhost:5005/")
machine.wait_for_unit("flame-seed.service")
machine.succeed("curl -f http://localhost:5005/api/apps | grep -q 'Test App'")
machine.succeed("curl -f http://localhost:5005/api/categories | grep -q 'Test Category'")
machine.succeed("curl -f http://localhost:5005/api/categories | grep -q Nixpkgs")
machine.succeed("curl -f http://localhost:5005/api/config | grep -q 'Test Flame'")
machine.succeed("curl -f http://localhost:5005/flame.css | grep -q '#123456'")
# Restart resilience
machine.succeed("systemctl restart flame.service")
machine.wait_for_unit("flame.service")
machine.wait_for_open_port(5005)
machine.succeed("curl -f http://localhost:5005/api/apps | grep -q 'Test App'")
# Freeform settings pass-through (unknown key, not explicitly declared)
machine.succeed("curl -f http://localhost:5005/api/config | grep -q customUnknownKey")
'';
}

View File

@@ -1,21 +1,21 @@
{ lib, ... }:
{
name = "hyphanet";
name = "freenet";
meta = {
maintainers = with lib.maintainers; [ nagy ];
};
nodes = {
machine = {
services.hyphanet.enable = true;
services.freenet.enable = true;
};
};
testScript = ''
machine.wait_for_unit("hyphanet.service")
machine.wait_for_unit("freenet.service")
machine.wait_for_open_port(8888)
machine.wait_until_succeeds("curl -sfL http://localhost:8888/ | grep Freenet")
machine.succeed("systemctl stop hyphanet")
machine.succeed("systemctl stop freenet")
'';
}

View File

@@ -1,5 +1,5 @@
{
gitea,
pkgs,
lib,
runTest,
...
@@ -28,18 +28,10 @@ let
];
makeGiteaTest =
type:
runTest {
imports = [
module
];
name = "${gitea.pname}-${type}";
nodes.server.services.gitea.settings.database = { inherit type; };
};
module =
{ config, ... }:
{
lib.nameValuePair type (runTest {
name = "${pkgs.gitea.pname}-${type}";
meta = {
inherit (gitea.meta) maintainers;
inherit (pkgs.gitea.meta) maintainers;
};
nodes = {
@@ -50,6 +42,7 @@ let
services = {
gitea = {
enable = true;
database = { inherit type; };
package = pkgs.gitea;
metricsTokenFile = (pkgs.writeText "metrics_secret" "fakesecret").outPath;
settings = {
@@ -77,7 +70,7 @@ let
testScript =
let
inherit (import ./ssh-keys.nix config.node.pkgs) snakeOilPrivateKey snakeOilPublicKey;
inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
in
/* python */ ''
GIT_SSH_COMMAND = "ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no"
@@ -105,7 +98,7 @@ let
server.succeed(
"su -l gitea -c 'gpg --homedir /var/lib/gitea/data/home/.gnupg "
+ "--import ${toString (config.node.pkgs.writeText "gitea.key" signingPrivateKey)}'"
+ "--import ${toString (pkgs.writeText "gitea.key" signingPrivateKey)}'"
)
assert "BEGIN PGP PUBLIC KEY BLOCK" in server.succeed("curl http://localhost:3000/api/v1/signing-key.gpg")
@@ -157,7 +150,7 @@ let
+ 'http://localhost:3000/metrics '
+ '| grep gitea_accesses')
'';
};
});
in
lib.genAttrs supportedDbTypes makeGiteaTest
lib.listToAttrs (map makeGiteaTest supportedDbTypes)

View File

@@ -1,154 +1,156 @@
{ lib, pkgs, ... }:
import ../make-test-python.nix (
{ lib, pkgs, ... }:
let
inherit (lib) mkMerge;
let
inherit (lib) mkMerge;
baseGrafanaConf = {
services.grafana = {
enable = true;
settings = {
analytics.reporting_enabled = false;
baseGrafanaConf = {
services.grafana = {
enable = true;
settings = {
analytics.reporting_enabled = false;
server = {
http_addr = "::1";
domain = "localhost";
};
server = {
http_addr = "::1";
domain = "localhost";
};
security = {
admin_user = "testadmin";
admin_password = "snakeoilpwd";
secret_key = "11111111111111111111";
security = {
admin_user = "testadmin";
admin_password = "snakeoilpwd";
secret_key = "11111111111111111111";
};
};
};
};
};
extraNodeConfs = {
sqlite = { };
extraNodeConfs = {
sqlite = { };
socket =
{ config, ... }:
{
services.grafana.settings.server = {
protocol = "socket";
socket = "/run/grafana/sock";
socket_gid = config.users.groups.nginx.gid;
socket =
{ config, ... }:
{
services.grafana.settings.server = {
protocol = "socket";
socket = "/run/grafana/sock";
socket_gid = config.users.groups.nginx.gid;
};
users.users.grafana.extraGroups = [ "nginx" ];
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts."_".locations."/".proxyPass = "http://unix:/run/grafana/sock";
};
};
users.users.grafana.extraGroups = [ "nginx" ];
declarativePlugins = {
services.grafana.declarativePlugins = [ pkgs.grafanaPlugins.grafana-clock-panel ];
};
services.nginx = {
postgresql = {
services.grafana.settings.database = {
host = "[::1]:5432";
user = "grafana";
};
services.postgresql = {
enable = true;
recommendedProxySettings = true;
virtualHosts."_".locations."/".proxyPass = "http://unix:/run/grafana/sock";
ensureDatabases = [ "grafana" ];
ensureUsers = [
{
name = "grafana";
ensureDBOwnership = true;
}
];
};
systemd.services.grafana.after = [ "postgresql.target" ];
};
declarativePlugins = {
services.grafana.declarativePlugins = [ pkgs.grafanaPlugins.grafana-clock-panel ];
mysql = {
services.grafana.settings.database.user = "grafana";
services.mysql = {
enable = true;
ensureDatabases = [ "grafana" ];
ensureUsers = [
{
name = "grafana";
ensurePermissions."grafana.*" = "ALL PRIVILEGES";
}
];
package = pkgs.mariadb;
};
systemd.services.grafana.after = [ "mysql.service" ];
};
};
postgresql = {
services.grafana.settings.database = {
host = "[::1]:5432";
user = "grafana";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "grafana" ];
ensureUsers = [
{
name = "grafana";
ensureDBOwnership = true;
}
];
};
systemd.services.grafana.after = [ "postgresql.target" ];
};
containers = builtins.mapAttrs (
_: val:
mkMerge [
val
baseGrafanaConf
]
) extraNodeConfs;
in
{
name = "grafana-basic";
mysql = {
services.grafana.settings.database.user = "grafana";
services.mysql = {
enable = true;
ensureDatabases = [ "grafana" ];
ensureUsers = [
{
name = "grafana";
ensurePermissions."grafana.*" = "ALL PRIVILEGES";
}
];
package = pkgs.mariadb;
};
systemd.services.grafana.after = [ "mysql.service" ];
};
};
meta.maintainers = [ ];
containers = builtins.mapAttrs (
_: val:
mkMerge [
val
baseGrafanaConf
]
) extraNodeConfs;
in
{
name = "grafana-basic";
inherit containers;
meta.maintainers = [ ];
testScript = ''
start_all()
inherit containers;
with subtest("Declarative plugins installed"):
declarativePlugins.wait_for_unit("grafana.service")
declarativePlugins.wait_for_open_port(3000, addr="::1")
declarativePlugins.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/plugins | grep grafana-clock-panel"
)
declarativePlugins.shutdown()
testScript = ''
start_all()
with subtest("Successful API query as admin user with sqlite db"):
sqlite.wait_for_unit("grafana.service")
sqlite.wait_for_open_port(3000)
print(sqlite.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users -i"
))
sqlite.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users | grep admin\@localhost"
)
sqlite.shutdown()
with subtest("Declarative plugins installed"):
declarativePlugins.wait_for_unit("grafana.service")
declarativePlugins.wait_for_open_port(3000, addr="::1")
declarativePlugins.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/plugins | grep grafana-clock-panel"
)
declarativePlugins.shutdown()
with subtest("Successful API query as admin user with sqlite db listening on socket"):
socket.wait_for_unit("grafana.service")
socket.wait_for_open_port(80)
print(socket.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]/api/org/users -i"
))
socket.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]/api/org/users | grep admin\@localhost"
)
socket.shutdown()
with subtest("Successful API query as admin user with sqlite db"):
sqlite.wait_for_unit("grafana.service")
sqlite.wait_for_open_port(3000)
print(sqlite.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users -i"
))
sqlite.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users | grep admin\@localhost"
)
sqlite.shutdown()
with subtest("Successful API query as admin user with postgresql db"):
postgresql.wait_for_unit("grafana.service")
postgresql.wait_for_unit("postgresql.target")
postgresql.wait_for_open_port(3000)
postgresql.wait_for_open_port(5432)
postgresql.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users | grep admin\@localhost"
)
postgresql.shutdown()
with subtest("Successful API query as admin user with sqlite db listening on socket"):
socket.wait_for_unit("grafana.service")
socket.wait_for_open_port(80)
print(socket.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]/api/org/users -i"
))
socket.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]/api/org/users | grep admin\@localhost"
)
socket.shutdown()
with subtest("Successful API query as admin user with postgresql db"):
postgresql.wait_for_unit("grafana.service")
postgresql.wait_for_unit("postgresql.target")
postgresql.wait_for_open_port(3000)
postgresql.wait_for_open_port(5432)
postgresql.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users | grep admin\@localhost"
)
postgresql.shutdown()
with subtest("Successful API query as admin user with mysql db"):
mysql.wait_for_unit("grafana.service")
mysql.wait_for_unit("mysql.service")
mysql.wait_for_open_port(3000)
mysql.wait_for_open_port(3306)
mysql.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users | grep admin\@localhost"
)
mysql.shutdown()
'';
}
with subtest("Successful API query as admin user with mysql db"):
mysql.wait_for_unit("grafana.service")
mysql.wait_for_unit("mysql.service")
mysql.wait_for_open_port(3000)
mysql.wait_for_open_port(3306)
mysql.succeed(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/org/users | grep admin\@localhost"
)
mysql.shutdown()
'';
}
)

View File

@@ -1,8 +1,10 @@
{
runTest,
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../../.. { inherit system config; },
}:
{
basic = runTest ./basic.nix;
provision = runTest ./provision;
basic = import ./basic.nix { inherit system pkgs; };
provision = import ./provision { inherit system pkgs; };
}

View File

@@ -1,247 +1,249 @@
{ lib, pkgs, ... }:
import ../../make-test-python.nix (
{ lib, pkgs, ... }:
let
inherit (lib) mkMerge;
let
inherit (lib) mkMerge;
baseGrafanaConf = {
services.grafana = {
enable = true;
provision.enable = true;
settings = {
analytics.reporting_enabled = false;
baseGrafanaConf = {
services.grafana = {
enable = true;
provision.enable = true;
settings = {
analytics.reporting_enabled = false;
server = {
http_addr = "::1";
domain = "localhost";
};
security = {
admin_user = "testadmin";
admin_password = "$__file{${pkgs.writeText "pwd" "snakeoilpwd"}}";
secret_key = "11111111111111111111";
};
};
};
systemd.tmpfiles.rules =
let
dashboard = pkgs.writeText "test.json" (builtins.readFile ./test_dashboard.json);
in
[
"d /var/lib/grafana/dashboards 0700 grafana grafana -"
"C+ /var/lib/grafana/dashboards/test.json - - - - ${dashboard}"
];
};
extraNodeConfs = {
provisionNix = {
services.grafana.provision = {
datasources.settings = {
apiVersion = 1;
datasources = [
{
name = "Test Datasource";
type = "testdata";
access = "proxy";
uid = "test_datasource";
}
];
};
dashboards.settings = {
apiVersion = 1;
providers = [
{
name = "default";
options.path = "/var/lib/grafana/dashboards";
}
];
};
alerting = {
rules.settings = {
groups = [
{
name = "test_rule_group";
folder = "test_folder";
interval = "60s";
rules = [
{
uid = "test_rule";
title = "Test Rule";
condition = "A";
data = [
{
refId = "A";
datasourceUid = "-100";
model = {
conditions = [
{
evaluator = {
params = [ 3 ];
type = "git";
};
operator.type = "and";
query.params = [ "A" ];
reducer.type = "last";
type = "query";
}
];
datasource = {
type = "__expr__";
uid = "-100";
};
expression = "1==0";
intervalMs = 1000;
maxDataPoints = 43200;
refId = "A";
type = "math";
};
}
];
for = "60s";
}
];
}
];
server = {
http_addr = "::1";
domain = "localhost";
};
contactPoints.settings = {
contactPoints = [
{
name = "Test Contact Point";
receivers = [
{
uid = "test_contact_point";
type = "prometheus-alertmanager";
settings.url = "http://localhost:9000";
}
];
}
];
};
policies.settings = {
policies = [
{
receiver = "Test Contact Point";
}
];
};
templates.settings = {
templates = [
{
name = "Test Template";
template = "Test message";
}
];
};
muteTimings.settings = {
muteTimes = [
{
name = "Test Mute Timing";
}
];
security = {
admin_user = "testadmin";
admin_password = "$__file{${pkgs.writeText "pwd" "snakeoilpwd"}}";
secret_key = "11111111111111111111";
};
};
};
systemd.tmpfiles.rules =
let
dashboard = pkgs.writeText "test.json" (builtins.readFile ./test_dashboard.json);
in
[
"d /var/lib/grafana/dashboards 0700 grafana grafana -"
"C+ /var/lib/grafana/dashboards/test.json - - - - ${dashboard}"
];
};
provisionYaml = {
services.grafana.provision = {
datasources.path = ./datasources.yaml;
dashboards.path = ./dashboards.yaml;
alerting = {
rules.path = ./rules.yaml;
contactPoints.path = ./contact-points.yaml;
policies.path = ./policies.yaml;
templates.path = ./templates.yaml;
muteTimings.path = ./mute-timings.yaml;
};
};
};
provisionYamlDirs =
let
mkdir = p: pkgs.writeTextDir (baseNameOf p) (builtins.readFile p);
in
{
extraNodeConfs = {
provisionNix = {
services.grafana.provision = {
datasources.path = mkdir ./datasources.yaml;
dashboards.path = mkdir ./dashboards.yaml;
datasources.settings = {
apiVersion = 1;
datasources = [
{
name = "Test Datasource";
type = "testdata";
access = "proxy";
uid = "test_datasource";
}
];
};
dashboards.settings = {
apiVersion = 1;
providers = [
{
name = "default";
options.path = "/var/lib/grafana/dashboards";
}
];
};
alerting = {
rules.path = mkdir ./rules.yaml;
contactPoints.path = mkdir ./contact-points.yaml;
policies.path = mkdir ./policies.yaml;
templates.path = mkdir ./templates.yaml;
muteTimings.path = mkdir ./mute-timings.yaml;
rules.settings = {
groups = [
{
name = "test_rule_group";
folder = "test_folder";
interval = "60s";
rules = [
{
uid = "test_rule";
title = "Test Rule";
condition = "A";
data = [
{
refId = "A";
datasourceUid = "-100";
model = {
conditions = [
{
evaluator = {
params = [ 3 ];
type = "git";
};
operator.type = "and";
query.params = [ "A" ];
reducer.type = "last";
type = "query";
}
];
datasource = {
type = "__expr__";
uid = "-100";
};
expression = "1==0";
intervalMs = 1000;
maxDataPoints = 43200;
refId = "A";
type = "math";
};
}
];
for = "60s";
}
];
}
];
};
contactPoints.settings = {
contactPoints = [
{
name = "Test Contact Point";
receivers = [
{
uid = "test_contact_point";
type = "prometheus-alertmanager";
settings.url = "http://localhost:9000";
}
];
}
];
};
policies.settings = {
policies = [
{
receiver = "Test Contact Point";
}
];
};
templates.settings = {
templates = [
{
name = "Test Template";
template = "Test message";
}
];
};
muteTimings.settings = {
muteTimes = [
{
name = "Test Mute Timing";
}
];
};
};
};
};
};
containers = builtins.mapAttrs (
_: val:
mkMerge [
val
baseGrafanaConf
]
) extraNodeConfs;
in
{
name = "grafana-provision";
provisionYaml = {
services.grafana.provision = {
datasources.path = ./datasources.yaml;
dashboards.path = ./dashboards.yaml;
alerting = {
rules.path = ./rules.yaml;
contactPoints.path = ./contact-points.yaml;
policies.path = ./policies.yaml;
templates.path = ./templates.yaml;
muteTimings.path = ./mute-timings.yaml;
};
};
};
meta.maintainers = [ ];
provisionYamlDirs =
let
mkdir = p: pkgs.writeTextDir (baseNameOf p) (builtins.readFile p);
in
{
services.grafana.provision = {
datasources.path = mkdir ./datasources.yaml;
dashboards.path = mkdir ./dashboards.yaml;
alerting = {
rules.path = mkdir ./rules.yaml;
contactPoints.path = mkdir ./contact-points.yaml;
policies.path = mkdir ./policies.yaml;
templates.path = mkdir ./templates.yaml;
muteTimings.path = mkdir ./mute-timings.yaml;
};
};
};
};
inherit containers;
containers = builtins.mapAttrs (
_: val:
mkMerge [
val
baseGrafanaConf
]
) extraNodeConfs;
in
{
name = "grafana-provision";
testScript = ''
start_all()
meta.maintainers = [ ];
nodeNix = ("Nix (new format)", provisionNix)
nodeYaml = ("Nix (YAML)", provisionYaml)
nodeYamlDir = ("Nix (YAML in dirs)", provisionYamlDirs)
inherit containers;
for description, machine in [nodeNix, nodeYaml, nodeYamlDir]:
with subtest(f"Should start provision node: {description}"):
machine.wait_for_unit("grafana.service")
machine.wait_for_open_port(3000, addr="::1")
testScript = ''
start_all()
with subtest(f"Successful datasource provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/datasources/uid/test_datasource | grep Test\ Datasource"
)
nodeNix = ("Nix (new format)", provisionNix)
nodeYaml = ("Nix (YAML)", provisionYaml)
nodeYamlDir = ("Nix (YAML in dirs)", provisionYamlDirs)
with subtest(f"Successful dashboard provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/dashboards/uid/test_dashboard | grep Test\ Dashboard"
)
for description, machine in [nodeNix, nodeYaml, nodeYamlDir]:
with subtest(f"Should start provision node: {description}"):
machine.wait_for_unit("grafana.service")
machine.wait_for_open_port(3000, addr="::1")
with subtest(f"Successful rule provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/alert-rules/test_rule | grep Test\ Rule"
)
with subtest(f"Successful datasource provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/datasources/uid/test_datasource | grep Test\ Datasource"
)
with subtest(f"Successful contact point provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/contact-points | grep Test\ Contact\ Point"
)
with subtest(f"Successful dashboard provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/dashboards/uid/test_dashboard | grep Test\ Dashboard"
)
with subtest(f"Successful policy provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/policies | grep Test\ Contact\ Point"
)
with subtest(f"Successful rule provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/alert-rules/test_rule | grep Test\ Rule"
)
with subtest(f"Successful template provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/templates | grep Test\ Template"
)
with subtest(f"Successful contact point provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/contact-points | grep Test\ Contact\ Point"
)
with subtest("Successful mute timings provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/mute-timings | grep Test\ Mute\ Timing"
)
'';
}
with subtest(f"Successful policy provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/policies | grep Test\ Contact\ Point"
)
with subtest(f"Successful template provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/templates | grep Test\ Template"
)
with subtest("Successful mute timings provision with {description}"):
machine.wait_until_succeeds(
"curl -sSfN -u testadmin:snakeoilpwd http://[::1]:3000/api/v1/provisioning/mute-timings | grep Test\ Mute\ Timing"
)
'';
}
)

View File

@@ -32,17 +32,21 @@
machine.succeed("curl -sSf http://localhost/")
machine.succeed(
"curl --cookie-jar cookies.txt -sSf -X POST http://localhost/login -d 'username=admin&password=admin'"
"curl -c cookies -sSf -X POST http://localhost/login -d 'username=admin&password=admin'"
)
cookie = machine.succeed(
"grep -v '^#' cookies | awk '{ print $7 }' | sed -e '/^$/d' | perl -pe 'chomp'"
)
machine.succeed(
"curl -sSf -X POST http://localhost/api/objects/tasks --cookie cookies.txt "
f"curl -sSf -X POST http://localhost/api/objects/tasks -b 'grocy_session={cookie}' "
+ '-d \'{"assigned_to_user_id":1,"name":"Test Task","due_date":"1970-01-01"}\'''
+ " --header 'Content-Type: application/json'"
)
task_name = machine.succeed(
"curl -sSf http://localhost/api/tasks --cookie cookies.txt --header 'Accept: application/json' | jq '.[].name' | xargs echo | perl -pe 'chomp'"
f"curl -sSf http://localhost/api/tasks -b 'grocy_session={cookie}' --header 'Accept: application/json' | jq '.[].name' | xargs echo | perl -pe 'chomp'"
)
assert task_name == "Test Task"
@@ -58,7 +62,7 @@
)
machine.succeed(
"curl -sSf -X 'PUT' --cookie cookies.txt "
f"curl -sSf -X 'PUT' -b 'grocy_session={cookie}' "
+ f" 'http://localhost/api/files/equipmentmanuals/{file_name_base64_urlencode}' "
+ " --header 'Accept: */*' "
+ " --header 'Content-Type: application/octet-stream' "
@@ -66,7 +70,7 @@
)
machine.succeed(
"curl -sSf -X 'GET' --cookie cookies.txt "
f"curl -sSf -X 'GET' -b 'grocy_session={cookie}' "
+ f" 'http://localhost/api/files/equipmentmanuals/{file_name_base64_urlencode}' "
+ " --header 'Accept: application/octet-stream' "
+ f" | cmp /tmp/{file_name}"

View File

@@ -1,4 +1,4 @@
{ handleTestOn, package }:
{ handleTestOn, package, ... }:
{
all = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./hadoop.nix {

View File

@@ -1,41 +0,0 @@
{ pkgs, ... }:
{
name = "hickory-dns";
meta.maintainers = with pkgs.lib.maintainers; [ adamcstephens ];
containers.machine = {
environment.systemPackages = [ pkgs.doggo ];
services.hickory-dns = {
enable = true;
settings.zones = [
{
zone = "example.test";
file = pkgs.writeText "example.test.zone" ''
$ORIGIN example.test.
$TTL 3600
@ IN SOA ns.example.test. hostmaster.example.test. (1 3600 600 86400 3600)
@ IN NS ns.example.test.
ns IN A 127.0.0.1
www IN A 192.0.2.1
'';
}
];
};
};
testScript = ''
import json
machine.start()
machine.wait_for_unit("hickory-dns.service")
machine.wait_for_open_port(53)
response = json.loads(machine.succeed("doggo @127.0.0.1 www.example.test. A --json"))
answers = response["responses"][0]["answers"]
assert [(answer["name"], answer["type"], answer["address"]) for answer in answers] == [
("www.example.test.", "A", "192.0.2.1")
], response
'';
}

View File

@@ -1,61 +0,0 @@
{ lib, ... }:
{
name = "iocaine";
meta.maintainers = with lib.maintainers; [ poz ];
nodes = {
iocaine_default = {
services.iocaine = {
enable = true;
};
};
reverse_proxy_integration = {
services.iocaine = {
enable = true;
settings.server.main = {
bind = "/run/iocaine/iocaine.socket";
unix-socket-access = "group";
mode = "http";
use = {
handler-from = "default";
};
};
settings.handler.default = { };
};
services.caddy = {
enable = true;
globalConfig = ''
http_port 8080
https_port 8081
'';
};
services.nginx.enable = true;
};
};
testScript = ''
start_all()
iocaine_default.wait_for_unit("iocaine.service")
iocaine_default.fail("curl -s --show-error --fail http://127.0.0.1:42069/random-path/yes/")
iocaine_default.fail("curl -s --show-error --fail http://127.0.0.1:42069/ -A 'Googlebot'")
iocaine_default.succeed("curl -s --show-error --fail http://127.0.0.1:42069/a/path/very/deep/into/the/forest/ -A 'Perplexity'")
iocaine_default.fail("curl -s --show-error --fail http://127.0.0.1:42042/metrics")
reverse_proxy_integration.wait_for_unit("iocaine.service")
reverse_proxy_integration.wait_for_unit("caddy.service")
reverse_proxy_integration.wait_for_unit("nginx.service")
reverse_proxy_integration.stop_job("nginx")
reverse_proxy_integration.stop_job("caddy")
reverse_proxy_integration.stop_job("iocaine")
reverse_proxy_integration.start_job("nginx")
reverse_proxy_integration.succeed("systemctl is-active iocaine.service")
reverse_proxy_integration.stop_job("nginx")
reverse_proxy_integration.stop_job("iocaine")
reverse_proxy_integration.start_job("caddy")
reverse_proxy_integration.succeed("systemctl is-active iocaine.service")
'';
}

View File

@@ -127,14 +127,14 @@
def api_get(path):
return f"curl --fail 'http://localhost:8096{path}' -H 'Authorization:{auth_header}'"
return f"curl --fail 'http://localhost:8096{path}' -H 'X-Emby-Authorization:{auth_header}'"
def api_post(path, json_file=None):
if json_file:
return f"curl --fail -X post 'http://localhost:8096{path}' -d '@{json_file}' -H Content-Type:application/json -H 'Authorization:{auth_header}'"
return f"curl --fail -X post 'http://localhost:8096{path}' -d '@{json_file}' -H Content-Type:application/json -H 'X-Emby-Authorization:{auth_header}'"
else:
return f"curl --fail -X post 'http://localhost:8096{path}' -H 'Authorization:{auth_header}'"
return f"curl --fail -X post 'http://localhost:8096{path}' -H 'X-Emby-Authorization:{auth_header}'"
# Test dashboard-based configuration verification
with subtest("Dashboard configuration verification"):
@@ -149,7 +149,7 @@
token = auth_result["AccessToken"]
def api_get_with_token(path):
return f"curl --fail 'http://localhost:8096{path}' -H 'Authorization:MediaBrowser Client=\"Test\", DeviceId=\"test\", Token={token}'"
return f"curl --fail 'http://localhost:8096{path}' -H 'X-Emby-Authorization:MediaBrowser Client=\"Test\", DeviceId=\"test\", Token={token}'"
# Get encoding config and verify key settings
config = json.loads(machineWithTranscoding.succeed(api_get_with_token("/System/Configuration/encoding")))
@@ -279,7 +279,7 @@
machine.succeed(
"ffmpeg"
+ f" -headers 'Authorization:{auth_header}'"
+ f" -headers 'X-Emby-Authorization:{auth_header}'"
+ f" -i http://localhost:8096/Videos/{video}/master.m3u8?mediaSourceId={media_source_id}"
+ " /tmp/test.mkv"
)

View File

@@ -1,17 +1,12 @@
{
pkgs,
runTest,
lib,
...
}:
{ pkgs, ... }:
with lib;
with pkgs.lib;
let
makeKafkaTest =
name:
{ kafkaPackage }:
(runTest {
(import ../make-test-python.nix {
inherit name;
nodes = {

View File

@@ -1,197 +1,199 @@
{ lib, pkgs, ... }:
import ../make-test-python.nix (
{ lib, pkgs, ... }:
let
inherit (lib) mkMerge;
let
inherit (lib) mkMerge;
# Generate with `kafka-storage.sh random-uuid`
clusterId = "ii5pZE5LRkSeWrnyBhMOYQ";
# Generate with `kafka-storage.sh random-uuid`
clusterId = "ii5pZE5LRkSeWrnyBhMOYQ";
kafkaConfig = {
networking.firewall.allowedTCPPorts = [
9092
9093
];
kafkaConfig = {
networking.firewall.allowedTCPPorts = [
9092
9093
];
virtualisation.diskSize = 1024;
virtualisation.memorySize = 1024 * 2;
virtualisation.diskSize = 1024;
virtualisation.memorySize = 1024 * 2;
environment.systemPackages = [ pkgs.apacheKafka ];
environment.systemPackages = [ pkgs.apacheKafka ];
services.apache-kafka = {
enable = true;
services.apache-kafka = {
enable = true;
clusterId = "${clusterId}";
clusterId = "${clusterId}";
formatLogDirs = true;
formatLogDirs = true;
settings = {
listeners = [
"PLAINTEXT://:9092"
"CONTROLLER://:9093"
];
"listener.security.protocol.map" = [
"PLAINTEXT:PLAINTEXT"
"CONTROLLER:PLAINTEXT"
];
"controller.quorum.voters" = lib.imap1 (i: name: "${toString i}@${name}:9093") (
builtins.attrNames kafkaNodes
);
"controller.listener.names" = [ "CONTROLLER" ];
settings = {
listeners = [
"PLAINTEXT://:9092"
"CONTROLLER://:9093"
];
"listener.security.protocol.map" = [
"PLAINTEXT:PLAINTEXT"
"CONTROLLER:PLAINTEXT"
];
"controller.quorum.voters" = lib.imap1 (i: name: "${toString i}@${name}:9093") (
builtins.attrNames kafkaNodes
);
"controller.listener.names" = [ "CONTROLLER" ];
"process.roles" = [
"broker"
"controller"
];
"process.roles" = [
"broker"
"controller"
];
"log.dirs" = [ "/var/lib/apache-kafka" ];
"num.partitions" = 6;
"offsets.topic.replication.factor" = 2;
"transaction.state.log.replication.factor" = 2;
"transaction.state.log.min.isr" = 2;
"log.dirs" = [ "/var/lib/apache-kafka" ];
"num.partitions" = 6;
"offsets.topic.replication.factor" = 2;
"transaction.state.log.replication.factor" = 2;
"transaction.state.log.min.isr" = 2;
};
};
systemd.services.apache-kafka = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
serviceConfig.StateDirectory = "apache-kafka";
};
};
systemd.services.apache-kafka = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
serviceConfig.StateDirectory = "apache-kafka";
};
};
extraKafkaConfig = {
kafka1 = {
services.apache-kafka.settings = {
"node.id" = 1;
"broker.rack" = 1;
};
};
extraKafkaConfig = {
kafka1 = {
services.apache-kafka.settings = {
"node.id" = 1;
"broker.rack" = 1;
kafka2 = {
services.apache-kafka.settings = {
"node.id" = 2;
"broker.rack" = 2;
};
};
kafka3 = {
services.apache-kafka.settings = {
"node.id" = 3;
"broker.rack" = 3;
};
};
kafka4 = {
services.apache-kafka.settings = {
"node.id" = 4;
"broker.rack" = 3;
};
};
};
kafka2 = {
services.apache-kafka.settings = {
"node.id" = 2;
"broker.rack" = 2;
};
kafkaNodes = builtins.mapAttrs (
_: val:
mkMerge [
val
kafkaConfig
]
) extraKafkaConfig;
in
{
name = "kafka-cluster";
meta = with pkgs.lib.maintainers; {
maintainers = [ jpds ];
};
kafka3 = {
services.apache-kafka.settings = {
"node.id" = 3;
"broker.rack" = 3;
};
nodes = {
inherit (kafkaNodes)
kafka1
kafka2
kafka3
kafka4
;
client =
{ config, ... }:
{
environment.systemPackages = [ pkgs.apacheKafka ];
virtualisation.diskSize = 1024;
};
};
kafka4 = {
services.apache-kafka.settings = {
"node.id" = 4;
"broker.rack" = 3;
};
};
};
testScript = ''
import json
kafkaNodes = builtins.mapAttrs (
_: val:
mkMerge [
val
kafkaConfig
]
) extraKafkaConfig;
in
{
name = "kafka-cluster";
meta = with pkgs.lib.maintainers; {
maintainers = [ jpds ];
};
for machine in kafka1, kafka2, kafka3, kafka4:
machine.wait_for_unit("apache-kafka")
nodes = {
inherit (kafkaNodes)
kafka1
kafka2
kafka3
kafka4
;
for machine in kafka1, kafka2, kafka3, kafka4:
machine.wait_for_open_port(9092)
machine.wait_for_open_port(9093)
client =
{ config, ... }:
{
environment.systemPackages = [ pkgs.apacheKafka ];
virtualisation.diskSize = 1024;
};
};
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Transition from STARTING to STARTED'"
)
testScript = ''
import json
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Kafka Server started'"
)
for machine in kafka1, kafka2, kafka3, kafka4:
machine.wait_for_unit("apache-kafka")
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'BrokerLifecycleManager' | grep 'Incarnation [[:graph:]]\+ of broker [[:digit:]] in cluster ${clusterId}'"
)
for machine in kafka1, kafka2, kafka3, kafka4:
machine.wait_for_open_port(9092)
machine.wait_for_open_port(9093)
current_voters_json = kafka1.wait_until_succeeds(
"kafka-metadata-quorum.sh --bootstrap-server kafka1:9092,kafka2:9092,kafka3:9092 describe --status | grep CurrentVoters"
).replace("CurrentVoters:", "")
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Transition from STARTING to STARTED'"
voters = json.loads(current_voters_json)
assert len(voters) == 4
kafka1.wait_until_succeeds(
"kafka-topics.sh --bootstrap-server kafka1:9092 --create --topic test-123 --replication-factor 2"
)
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Kafka Server started'"
for machine in kafka1, kafka2, kafka3, kafka4:
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep -E 'Created log for partition test-123-[[:digit:]] in /var/lib/apache-kafka/test-123-[[:digit:]] with properties'"
)
kafka1.wait_until_succeeds(
"kafka-topics.sh --bootstrap-server=kafka1:9092 --describe --topic test-123 | "
+ "grep 'PartitionCount: 6'"
)
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'BrokerLifecycleManager' | grep 'Incarnation [[:graph:]]\+ of broker [[:digit:]] in cluster ${clusterId}'"
# Should never see a replica on both 3 and 4 as they're in the same rack
kafka1.fail(
"kafka-topics.sh --bootstrap-server=kafka1:9092 --describe --topic test-123 | "
+ "grep -E 'Replicas: (3,4|4,3)'"
)
current_voters_json = kafka1.wait_until_succeeds(
"kafka-metadata-quorum.sh --bootstrap-server kafka1:9092,kafka2:9092,kafka3:9092 describe --status | grep CurrentVoters"
).replace("CurrentVoters:", "")
voters = json.loads(current_voters_json)
assert len(voters) == 4
kafka1.wait_until_succeeds(
"kafka-topics.sh --bootstrap-server kafka1:9092 --create --topic test-123 --replication-factor 2"
)
for machine in kafka1, kafka2, kafka3, kafka4:
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep -E 'Created log for partition test-123-[[:digit:]] in /var/lib/apache-kafka/test-123-[[:digit:]] with properties'"
client.succeed(
"echo 'test 2' | "
+ "kafka-console-producer.sh "
+ "--bootstrap-server kafka1:9092 "
+ "--topic test-123"
)
assert "test 2" in client.succeed(
"kafka-console-consumer.sh "
+ "--bootstrap-server kafka2:9092 --topic test-123 "
+ "--group readtest "
+ "--from-beginning --max-messages 1"
)
kafka1.wait_until_succeeds(
"kafka-topics.sh --bootstrap-server=kafka1:9092 --describe --topic test-123 | "
+ "grep 'PartitionCount: 6'"
)
# Should never see a replica on both 3 and 4 as they're in the same rack
kafka1.fail(
"kafka-topics.sh --bootstrap-server=kafka1:9092 --describe --topic test-123 | "
+ "grep -E 'Replicas: (3,4|4,3)'"
)
client.succeed(
"echo 'test 2' | "
+ "kafka-console-producer.sh "
+ "--bootstrap-server kafka1:9092 "
+ "--topic test-123"
)
assert "test 2" in client.succeed(
"kafka-console-consumer.sh "
+ "--bootstrap-server kafka2:9092 --topic test-123 "
+ "--group readtest "
+ "--from-beginning --max-messages 1"
)
client.succeed(
"echo 'test 3' | "
+ "kafka-console-producer.sh "
+ "--bootstrap-server kafka2:9092 "
+ "--topic test-123"
)
assert "test 3" in client.succeed(
"kafka-console-consumer.sh "
+ "--bootstrap-server kafka3:9092 --topic test-123 "
+ "--group readtest "
+ "--max-messages 1"
)
'';
}
client.succeed(
"echo 'test 3' | "
+ "kafka-console-producer.sh "
+ "--bootstrap-server kafka2:9092 "
+ "--topic test-123"
)
assert "test 3" in client.succeed(
"kafka-console-consumer.sh "
+ "--bootstrap-server kafka3:9092 --topic test-123 "
+ "--group readtest "
+ "--max-messages 1"
)
'';
}
)

View File

@@ -1,13 +1,11 @@
{
runTest,
pkgs,
system ? builtins.currentSystem,
config ? { },
pkgs ? import ../../.. { inherit system config; },
}:
{
base = import ./base.nix {
inherit pkgs runTest;
inherit (pkgs) lib;
};
cluster = runTest ./cluster.nix;
mirrormaker = runTest ./mirrormaker.nix;
base = import ./base.nix { inherit system pkgs; };
cluster = import ./cluster.nix { inherit system pkgs; };
mirrormaker = import ./mirrormaker.nix { inherit system pkgs; };
}

View File

@@ -1,238 +1,240 @@
{ lib, pkgs, ... }:
import ../make-test-python.nix (
{ lib, pkgs, ... }:
let
inherit (lib) mkMerge;
let
inherit (lib) mkMerge;
# Generate with `kafka-storage.sh random-uuid`
clusterAId = "ihzlrasUQ9O3Yy0ZWYkd6w";
# Generate with `kafka-storage.sh random-uuid`
clusterAId = "ihzlrasUQ9O3Yy0ZWYkd6w";
clusterBId = "Bnu_zrzKRH6-7KcK7t3I5Q";
clusterBId = "Bnu_zrzKRH6-7KcK7t3I5Q";
kafkaConfig = {
networking.firewall.allowedTCPPorts = [
9092
9093
];
kafkaConfig = {
networking.firewall.allowedTCPPorts = [
9092
9093
];
virtualisation.diskSize = 1024;
virtualisation.memorySize = 1024 * 2;
virtualisation.diskSize = 1024;
virtualisation.memorySize = 1024 * 2;
environment.systemPackages = [ pkgs.apacheKafka ];
environment.systemPackages = [ pkgs.apacheKafka ];
services.apache-kafka = {
enable = true;
formatLogDirs = true;
settings = {
listeners = [
"PLAINTEXT://:9092"
"CONTROLLER://:9093"
];
"listener.security.protocol.map" = [
"PLAINTEXT:PLAINTEXT"
"CONTROLLER:PLAINTEXT"
];
"controller.listener.names" = [ "CONTROLLER" ];
"process.roles" = [
"broker"
"controller"
];
"log.dirs" = [ "/var/lib/apache-kafka" ];
"num.partitions" = 1;
"offsets.topic.replication.factor" = 1;
"transaction.state.log.replication.factor" = 1;
"transaction.state.log.min.isr" = 1;
};
};
systemd.services.apache-kafka = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
serviceConfig.StateDirectory = "apache-kafka";
};
};
extraKafkaConfig = {
kafkaa1 = {
services.apache-kafka = {
clusterId = "${clusterAId}";
enable = true;
formatLogDirs = true;
settings = {
"node.id" = 1;
"controller.quorum.voters" = [ "1@kafkaa1:9093" ];
listeners = [
"PLAINTEXT://:9092"
"CONTROLLER://:9093"
];
"listener.security.protocol.map" = [
"PLAINTEXT:PLAINTEXT"
"CONTROLLER:PLAINTEXT"
];
"controller.listener.names" = [ "CONTROLLER" ];
"process.roles" = [
"broker"
"controller"
];
"log.dirs" = [ "/var/lib/apache-kafka" ];
"num.partitions" = 1;
"offsets.topic.replication.factor" = 1;
"transaction.state.log.replication.factor" = 1;
"transaction.state.log.min.isr" = 1;
};
};
systemd.services.apache-kafka = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
serviceConfig.StateDirectory = "apache-kafka";
};
};
kafkab1 = {
services.apache-kafka = {
clusterId = "${clusterBId}";
extraKafkaConfig = {
kafkaa1 = {
services.apache-kafka = {
clusterId = "${clusterAId}";
settings = {
"node.id" = 1;
"controller.quorum.voters" = [ "1@kafkab1:9093" ];
};
};
};
};
kafkaNodes = builtins.mapAttrs (
_: val:
mkMerge [
val
kafkaConfig
]
) extraKafkaConfig;
mirrorMakerProperties = pkgs.writeText "mm2.properties" ''
name = A->B
clusters = A, B
A.bootstrap.servers = kafkaa1:9092
B.bootstrap.servers = kafkab1:9092
A->B.enabled = true
A->B.topics = .*
B->A.enabled = false
B->A.topics = .*
replication.factor=1
replication.policy.class=org.apache.kafka.connect.mirror.IdentityReplicationPolicy
tasks.max = 2
refresh.topics.enabled = true
refresh.topics.interval.seconds = 5
sync.topic.configs.enabled = true
checkpoints.topic.replication.factor=1
heartbeats.topic.replication.factor=1
offset-syncs.topic.replication.factor=1
offset.storage.replication.factor=1
status.storage.replication.factor=1
config.storage.replication.factor=1
emit.checkpoints.enabled = true
emit.checkpoints.interval.seconds = 5
'';
in
{
name = "kafka-mirrormaker";
meta = with pkgs.lib.maintainers; {
maintainers = [ jpds ];
};
nodes = {
inherit (kafkaNodes) kafkaa1 kafkab1;
mirrormaker =
{ config, ... }:
{
virtualisation.diskSize = 1024;
virtualisation.memorySize = 1024 * 2;
# Define a mirrormaker systemd service
systemd.services.kafka-connect-mirror-maker = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkgs.apacheKafka}/bin/connect-mirror-maker.sh ${mirrorMakerProperties}
'';
Restart = "on-failure";
RestartSec = "5s";
settings = {
"node.id" = 1;
"controller.quorum.voters" = [ "1@kafkaa1:9093" ];
};
};
};
};
testScript = ''
import json
kafkab1 = {
services.apache-kafka = {
clusterId = "${clusterBId}";
for machine in kafkaa1, kafkab1:
machine.wait_for_unit("apache-kafka")
settings = {
"node.id" = 1;
"controller.quorum.voters" = [ "1@kafkab1:9093" ];
};
};
};
};
for machine in kafkaa1, kafkab1:
machine.wait_for_open_port(9092)
machine.wait_for_open_port(9093)
kafkaNodes = builtins.mapAttrs (
_: val:
mkMerge [
val
kafkaConfig
]
) extraKafkaConfig;
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Transition from STARTING to STARTED'"
mirrorMakerProperties = pkgs.writeText "mm2.properties" ''
name = A->B
clusters = A, B
A.bootstrap.servers = kafkaa1:9092
B.bootstrap.servers = kafkab1:9092
A->B.enabled = true
A->B.topics = .*
B->A.enabled = false
B->A.topics = .*
replication.factor=1
replication.policy.class=org.apache.kafka.connect.mirror.IdentityReplicationPolicy
tasks.max = 2
refresh.topics.enabled = true
refresh.topics.interval.seconds = 5
sync.topic.configs.enabled = true
checkpoints.topic.replication.factor=1
heartbeats.topic.replication.factor=1
offset-syncs.topic.replication.factor=1
offset.storage.replication.factor=1
status.storage.replication.factor=1
config.storage.replication.factor=1
emit.checkpoints.enabled = true
emit.checkpoints.interval.seconds = 5
'';
in
{
name = "kafka-mirrormaker";
meta = with pkgs.lib.maintainers; {
maintainers = [ jpds ];
};
nodes = {
inherit (kafkaNodes) kafkaa1 kafkab1;
mirrormaker =
{ config, ... }:
{
virtualisation.diskSize = 1024;
virtualisation.memorySize = 1024 * 2;
# Define a mirrormaker systemd service
systemd.services.kafka-connect-mirror-maker = {
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkgs.apacheKafka}/bin/connect-mirror-maker.sh ${mirrorMakerProperties}
'';
Restart = "on-failure";
RestartSec = "5s";
};
};
};
};
testScript = ''
import json
for machine in kafkaa1, kafkab1:
machine.wait_for_unit("apache-kafka")
for machine in kafkaa1, kafkab1:
machine.wait_for_open_port(9092)
machine.wait_for_open_port(9093)
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Transition from STARTING to STARTED'"
)
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Kafka Server started'"
)
for machine in kafkaa1, kafkab1:
current_voters_json = machine.wait_until_succeeds(
f"kafka-metadata-quorum.sh --bootstrap-server {machine.name}:9092 describe --status | grep CurrentVoters"
).replace("CurrentVoters:", "")
voters = json.loads(current_voters_json)
assert len(voters) == 1
mirrormaker.wait_for_unit("kafka-connect-mirror-maker")
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Kafka MirrorMaker initializing'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Targeting clusters \[A, B\]'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'INFO \[Worker clientId=A->B, groupId=A-mm2\] Finished starting connectors and tasks'"
)
machine.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Kafka Server started'"
mirrormaker.wait_until_succeeds(
"""
journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'INFO \[MirrorSourceConnector\|task-0\] \[Producer clientId=A->B\|A->B-0\|offset-syncs-source-producer\] Cluster ID: ${clusterAId}'
"""
)
for machine in kafkaa1, kafkab1:
current_voters_json = machine.wait_until_succeeds(
f"kafka-metadata-quorum.sh --bootstrap-server {machine.name}:9092 describe --status | grep CurrentVoters"
).replace("CurrentVoters:", "")
voters = json.loads(current_voters_json)
assert len(voters) == 1
mirrormaker.wait_for_unit("kafka-connect-mirror-maker")
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Kafka MirrorMaker initializing'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Targeting clusters \[A, B\]'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'INFO \[Worker clientId=A->B, groupId=A-mm2\] Finished starting connectors and tasks'"
)
mirrormaker.wait_until_succeeds(
"""
journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'INFO \[MirrorSourceConnector\|task-0\] \[Producer clientId=A->B\|A->B-0\|offset-syncs-source-producer\] Cluster ID: ${clusterAId}'
"""
)
kafkaa1.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Stabilized group B-mm2'"
)
kafkab1.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Stabilized group A-mm2'"
)
kafkaa1.wait_until_succeeds(
"kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-mm-1 --partitions 1 --replication-factor 1"
)
for machine in kafkaa1, kafkab1:
machine.succeed(
"kafka-topics.sh --bootstrap-server localhost:9092 --list | grep 'test-mm-1'"
kafkaa1.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Stabilized group B-mm2'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'replicating [[:digit:]]\+ topic-partitions A->B: \[test-mm-1-0\]'"
)
kafkab1.wait_until_succeeds(
"journalctl -o cat -u apache-kafka.service | grep 'Stabilized group A-mm2'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Found [[:digit:]]\+ new topic-partitions on A'"
)
kafkaa1.wait_until_succeeds(
"kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-mm-1 --partitions 1 --replication-factor 1"
)
kafkaa1.wait_until_succeeds(
"kafka-verifiable-producer.sh --bootstrap-server kafkaa1:9092 --throughput 10 --max-messages 100 --topic test-mm-1"
)
for machine in kafkaa1, kafkab1:
machine.succeed(
"kafka-topics.sh --bootstrap-server localhost:9092 --list | grep 'test-mm-1'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Committing offsets for [[:digit:]]\+ acknowledged messages'"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'replicating [[:digit:]]\+ topic-partitions A->B: \[test-mm-1-0\]'"
)
kafkab1.wait_until_succeeds(
"kafka-verifiable-consumer.sh --bootstrap-server kafkab1:9092 --topic test-mm-1 --group-id testreplication --max-messages 100"
)
'';
}
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Found [[:digit:]]\+ new topic-partitions on A'"
)
kafkaa1.wait_until_succeeds(
"kafka-verifiable-producer.sh --bootstrap-server kafkaa1:9092 --throughput 10 --max-messages 100 --topic test-mm-1"
)
mirrormaker.wait_until_succeeds(
"journalctl -o cat -u kafka-connect-mirror-maker.service | grep 'Committing offsets for [[:digit:]]\+ acknowledged messages'"
)
kafkab1.wait_until_succeeds(
"kafka-verifiable-consumer.sh --bootstrap-server kafkab1:9092 --topic test-mm-1 --group-id testreplication --max-messages 100"
)
'';
}
)

View File

@@ -1,9 +1,9 @@
{
pkgs,
runTest,
system ? builtins.currentSystem,
pkgs ? import ../../.. { inherit system; },
}:
{
mit = runTest ./mit.nix;
heimdal = runTest ./heimdal.nix;
ldap = import ./ldap { inherit pkgs runTest; };
mit = import ./mit.nix { inherit system pkgs; };
heimdal = import ./heimdal.nix { inherit system pkgs; };
ldap = import ./ldap { inherit system pkgs; };
}

View File

@@ -1,257 +1,259 @@
{ pkgs, ... }:
{
name = "kerberos_server-heimdal";
import ../make-test-python.nix (
{ pkgs, ... }:
{
name = "kerberos_server-heimdal";
nodes = {
server =
{ config, pkgs, ... }:
{
imports = [ ../common/user-account.nix ];
nodes = {
server =
{ config, pkgs, ... }:
{
imports = [ ../common/user-account.nix ];
users.users.alice.extraGroups = [ "wheel" ];
users.users.alice.extraGroups = [ "wheel" ];
services.getty.autologinUser = "alice";
services.getty.autologinUser = "alice";
virtualisation.vlans = [ 1 ];
virtualisation.vlans = [ 1 ];
time.timeZone = "Etc/UTC";
time.timeZone = "Etc/UTC";
networking = {
domain = "foo.bar";
useDHCP = false;
firewall.enable = false;
hosts."10.0.0.1" = [ "server.foo.bar" ];
hosts."10.0.0.2" = [ "client.foo.bar" ];
};
networking = {
domain = "foo.bar";
useDHCP = false;
firewall.enable = false;
hosts."10.0.0.1" = [ "server.foo.bar" ];
hosts."10.0.0.2" = [ "client.foo.bar" ];
};
systemd.network.networks."01-eth1" = {
name = "eth1";
networkConfig.Address = "10.0.0.1/24";
};
systemd.network.networks."01-eth1" = {
name = "eth1";
networkConfig.Address = "10.0.0.1/24";
};
security.krb5 = {
enable = true;
package = pkgs.heimdal;
settings = {
libdefaults.default_realm = "FOO.BAR";
security.krb5 = {
enable = true;
package = pkgs.heimdal;
settings = {
libdefaults.default_realm = "FOO.BAR";
# Enable extra debug output
logging = {
admin_server = "SYSLOG:DEBUG:AUTH";
default = "SYSLOG:DEBUG:AUTH";
kdc = "SYSLOG:DEBUG:AUTH";
# Enable extra debug output
logging = {
admin_server = "SYSLOG:DEBUG:AUTH";
default = "SYSLOG:DEBUG:AUTH";
kdc = "SYSLOG:DEBUG:AUTH";
};
realms = {
"FOO.BAR" = {
admin_server = "server.foo.bar";
kpasswd_server = "server.foo.bar";
kdc = [ "server.foo.bar" ];
};
};
};
};
realms = {
services.kerberos_server = {
enable = true;
settings.realms = {
"FOO.BAR" = {
admin_server = "server.foo.bar";
kpasswd_server = "server.foo.bar";
kdc = [ "server.foo.bar" ];
acl = [
{
principal = "kadmin/admin@FOO.BAR";
access = "all";
}
{
principal = "alice/admin@FOO.BAR";
access = [
"add"
"cpw"
"delete"
"get"
"list"
"modify"
];
}
];
};
};
};
};
services.kerberos_server = {
enable = true;
settings.realms = {
"FOO.BAR" = {
acl = [
{
principal = "kadmin/admin@FOO.BAR";
access = "all";
}
{
principal = "alice/admin@FOO.BAR";
access = [
"add"
"cpw"
"delete"
"get"
"list"
"modify"
];
}
];
};
client =
{ config, pkgs, ... }:
{
imports = [ ../common/user-account.nix ];
users.users.alice.extraGroups = [ "wheel" ];
services.getty.autologinUser = "alice";
virtualisation.vlans = [ 1 ];
time.timeZone = "Etc/UTC";
networking = {
domain = "foo.bar";
useDHCP = false;
hosts."10.0.0.1" = [ "server.foo.bar" ];
hosts."10.0.0.2" = [ "client.foo.bar" ];
};
};
};
client =
{ config, pkgs, ... }:
{
imports = [ ../common/user-account.nix ];
systemd.network.networks."01-eth1" = {
name = "eth1";
networkConfig.Address = "10.0.0.2/24";
};
users.users.alice.extraGroups = [ "wheel" ];
security.krb5 = {
enable = true;
package = pkgs.heimdal;
settings = {
libdefaults.default_realm = "FOO.BAR";
services.getty.autologinUser = "alice";
logging = {
admin_server = "SYSLOG:DEBUG:AUTH";
default = "SYSLOG:DEBUG:AUTH";
kdc = "SYSLOG:DEBUG:AUTH";
};
virtualisation.vlans = [ 1 ];
time.timeZone = "Etc/UTC";
networking = {
domain = "foo.bar";
useDHCP = false;
hosts."10.0.0.1" = [ "server.foo.bar" ];
hosts."10.0.0.2" = [ "client.foo.bar" ];
};
systemd.network.networks."01-eth1" = {
name = "eth1";
networkConfig.Address = "10.0.0.2/24";
};
security.krb5 = {
enable = true;
package = pkgs.heimdal;
settings = {
libdefaults.default_realm = "FOO.BAR";
logging = {
admin_server = "SYSLOG:DEBUG:AUTH";
default = "SYSLOG:DEBUG:AUTH";
kdc = "SYSLOG:DEBUG:AUTH";
};
realms = {
"FOO.BAR" = {
admin_server = "server.foo.bar";
kpasswd_server = "server.foo.bar";
kdc = [ "server.foo.bar" ];
realms = {
"FOO.BAR" = {
admin_server = "server.foo.bar";
kpasswd_server = "server.foo.bar";
kdc = [ "server.foo.bar" ];
};
};
};
};
};
};
};
};
testScript =
{ nodes, ... }:
''
import string
import random
random.seed(0)
testScript =
{ nodes, ... }:
''
import string
import random
random.seed(0)
start_all()
start_all()
with subtest("Server: initialize realm"):
# for unit in ["kadmind.service", "kdc.socket", "kpasswdd.socket"]:
for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]:
server.wait_for_unit(unit)
with subtest("Server: initialize realm"):
# for unit in ["kadmind.service", "kdc.socket", "kpasswdd.socket"]:
for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]:
server.wait_for_unit(unit)
server.succeed("kadmin -l init --realm-max-ticket-life='8 day' --realm-max-renewable-life='10 day' FOO.BAR")
server.succeed("kadmin -l init --realm-max-ticket-life='8 day' --realm-max-renewable-life='10 day' FOO.BAR")
for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]:
server.systemctl(f"restart {unit}")
for unit in ["kadmind.service", "kdc.service", "kpasswdd.service"]:
server.systemctl(f"restart {unit}")
alice_krb_pw = "alice_hunter2"
alice_old_krb_pw = ""
alice_krb_admin_pw = "alice_admin_hunter2"
alice_krb_pw = "alice_hunter2"
alice_old_krb_pw = ""
alice_krb_admin_pw = "alice_admin_hunter2"
def random_password():
password_chars = string.ascii_letters + string.digits + string.punctuation.replace('"', "")
return "".join(random.choice(password_chars) for _ in range(16))
def random_password():
password_chars = string.ascii_letters + string.digits + string.punctuation.replace('"', "")
return "".join(random.choice(password_chars) for _ in range(16))
with subtest("Server: initialize user principals and keytabs"):
server.succeed(f'kadmin -l add --password="{alice_krb_admin_pw}" --use-defaults alice/admin')
server.succeed("kadmin -l ext_keytab --keytab=admin.keytab alice/admin")
with subtest("Server: initialize user principals and keytabs"):
server.succeed(f'kadmin -l add --password="{alice_krb_admin_pw}" --use-defaults alice/admin')
server.succeed("kadmin -l ext_keytab --keytab=admin.keytab alice/admin")
server.succeed(f'kadmin -p alice/admin -K admin.keytab add --password="{alice_krb_pw}" --use-defaults alice')
server.succeed("kadmin -l ext_keytab --keytab=alice.keytab alice")
server.succeed(f'kadmin -p alice/admin -K admin.keytab add --password="{alice_krb_pw}" --use-defaults alice')
server.succeed("kadmin -l ext_keytab --keytab=alice.keytab alice")
server.wait_for_unit("getty@tty1.service")
server.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
server.wait_for_unit("default.target")
server.wait_for_unit("getty@tty1.service")
server.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
server.wait_for_unit("default.target")
with subtest("Server: initialize host principal with keytab"):
server.send_chars("sudo ktutil get -p alice/admin host/server.foo.bar\n")
server.wait_until_tty_matches("1", "password for alice:")
server.send_chars("${nodes.server.users.users.alice.password}\n")
server.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:")
server.send_chars(f'{alice_krb_admin_pw}\n')
server.wait_for_file("/etc/krb5.keytab")
with subtest("Server: initialize host principal with keytab"):
server.send_chars("sudo ktutil get -p alice/admin host/server.foo.bar\n")
server.wait_until_tty_matches("1", "password for alice:")
server.send_chars("${nodes.server.users.users.alice.password}\n")
server.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:")
server.send_chars(f'{alice_krb_admin_pw}\n')
server.wait_for_file("/etc/krb5.keytab")
ktutil_list = server.succeed("sudo ktutil list")
if not "host/server.foo.bar" in ktutil_list:
exit(1)
ktutil_list = server.succeed("sudo ktutil list")
if not "host/server.foo.bar" in ktutil_list:
exit(1)
server.send_chars("clear\n")
server.send_chars("clear\n")
client.systemctl("start network-online.target")
client.wait_for_unit("network-online.target")
client.wait_for_unit("getty@tty1.service")
client.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
client.wait_for_unit("default.target")
client.systemctl("start network-online.target")
client.wait_for_unit("network-online.target")
client.wait_for_unit("getty@tty1.service")
client.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
client.wait_for_unit("default.target")
with subtest("Client: initialize host principal with keytab"):
client.succeed(
f'echo "{alice_krb_admin_pw}" > pw.txt',
"kinit -p --password-file=pw.txt alice/admin",
)
with subtest("Client: initialize host principal with keytab"):
client.succeed(
f'echo "{alice_krb_admin_pw}" > pw.txt',
"kinit -p --password-file=pw.txt alice/admin",
)
client.send_chars("sudo ktutil get -p alice/admin host/client.foo.bar\n")
client.wait_until_tty_matches("1", "password for alice:")
client.send_chars("${nodes.client.users.users.alice.password}\n")
client.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:")
client.send_chars(f"{alice_krb_admin_pw}\n")
client.wait_for_file("/etc/krb5.keytab")
client.send_chars("sudo ktutil get -p alice/admin host/client.foo.bar\n")
client.wait_until_tty_matches("1", "password for alice:")
client.send_chars("${nodes.client.users.users.alice.password}\n")
client.wait_until_tty_matches("1", "alice/admin@FOO.BAR's Password:")
client.send_chars(f"{alice_krb_admin_pw}\n")
client.wait_for_file("/etc/krb5.keytab")
ktutil_list = client.succeed("sudo ktutil list")
if not "host/client.foo.bar" in ktutil_list:
exit(1)
ktutil_list = client.succeed("sudo ktutil list")
if not "host/client.foo.bar" in ktutil_list:
exit(1)
client.send_chars("clear\n")
client.send_chars("clear\n")
with subtest("Client: kinit alice"):
client.succeed(
f"echo '{alice_krb_pw}' > pw.txt",
"kinit -p --password-file=pw.txt alice",
)
tickets = client.succeed("klist")
assert "Principal: alice@FOO.BAR" in tickets
client.send_chars("clear\n")
with subtest("Client: kinit alice"):
client.succeed(
f"echo '{alice_krb_pw}' > pw.txt",
"kinit -p --password-file=pw.txt alice",
)
tickets = client.succeed("klist")
assert "Principal: alice@FOO.BAR" in tickets
client.send_chars("clear\n")
with subtest("Client: kpasswd alice"):
alice_old_krb_pw = alice_krb_pw
alice_krb_pw = random_password()
client.send_chars("kpasswd\n")
client.wait_until_tty_matches("1", "alice@FOO.BAR's Password:")
client.send_chars(f"{alice_old_krb_pw}\n", 0.1)
client.wait_until_tty_matches("1", "New password:")
client.send_chars(f"{alice_krb_pw}\n", 0.1)
client.wait_until_tty_matches("1", "Verify password - New password:")
client.send_chars(f"{alice_krb_pw}\n", 0.1)
with subtest("Client: kpasswd alice"):
alice_old_krb_pw = alice_krb_pw
alice_krb_pw = random_password()
client.send_chars("kpasswd\n")
client.wait_until_tty_matches("1", "alice@FOO.BAR's Password:")
client.send_chars(f"{alice_old_krb_pw}\n", 0.1)
client.wait_until_tty_matches("1", "New password:")
client.send_chars(f"{alice_krb_pw}\n", 0.1)
client.wait_until_tty_matches("1", "Verify password - New password:")
client.send_chars(f"{alice_krb_pw}\n", 0.1)
client.wait_until_tty_matches("1", "Success : Password changed")
client.wait_until_tty_matches("1", "Success : Password changed")
client.send_chars("clear\n")
client.send_chars("clear\n")
with subtest("Server: kinit alice"):
server.succeed(
"echo 'alice_pw_2' > pw.txt"
"kinit -p --password-file=pw.txt alice",
)
tickets = client.succeed("klist")
assert "Principal: alice@FOO.BAR" in tickets
server.send_chars("clear\n")
with subtest("Server: kinit alice"):
server.succeed(
"echo 'alice_pw_2' > pw.txt"
"kinit -p --password-file=pw.txt alice",
)
tickets = client.succeed("klist")
assert "Principal: alice@FOO.BAR" in tickets
server.send_chars("clear\n")
with subtest("Server: kpasswd alice"):
alice_old_krb_pw = alice_krb_pw
alice_krb_pw = random_password()
server.send_chars("kpasswd\n")
server.wait_until_tty_matches("1", "alice@FOO.BAR's Password:")
server.send_chars(f"{alice_old_krb_pw}\n", 0.1)
server.wait_until_tty_matches("1", "New password:")
server.send_chars(f"{alice_krb_pw}\n", 0.1)
server.wait_until_tty_matches("1", "Verify password - New password:")
server.send_chars(f"{alice_krb_pw}\n", 0.1)
with subtest("Server: kpasswd alice"):
alice_old_krb_pw = alice_krb_pw
alice_krb_pw = random_password()
server.send_chars("kpasswd\n")
server.wait_until_tty_matches("1", "alice@FOO.BAR's Password:")
server.send_chars(f"{alice_old_krb_pw}\n", 0.1)
server.wait_until_tty_matches("1", "New password:")
server.send_chars(f"{alice_krb_pw}\n", 0.1)
server.wait_until_tty_matches("1", "Verify password - New password:")
server.send_chars(f"{alice_krb_pw}\n", 0.1)
server.wait_until_tty_matches("1", "Success : Password changed")
server.wait_until_tty_matches("1", "Success : Password changed")
server.send_chars("clear\n")
'';
server.send_chars("clear\n")
'';
meta.maintainers = pkgs.heimdal.meta.maintainers;
}
meta.maintainers = pkgs.heimdal.meta.maintainers;
}
)

View File

@@ -1,7 +1,7 @@
{
pkgs,
runTest,
system ? builtins.currentSystem,
pkgs ? import ../../../.. { inherit system; },
}:
{
mit = runTest ./mit.nix;
mit = import ./mit.nix { inherit system pkgs; };
}

View File

@@ -1,190 +1,192 @@
{ pkgs, ... }:
let
DITRoot = "dc=example,dc=com";
realm = "EXAMPLE.COM";
import ../../make-test-python.nix (
{ pkgs, ... }:
let
DITRoot = "dc=example,dc=com";
realm = "EXAMPLE.COM";
krb5Package = pkgs.krb5.override { withLdap = true; };
krb5Package = pkgs.krb5.override { withLdap = true; };
# Password used by Kerberos services to bind to their identities
krbSrvPwd = "kerberos_service_password";
# Stash file read by Kerberos daemons containing the service password
# DO NOT DO THIS IN PRODUCTION! The stash file is a fundamental secret!
krbPwdStash = pkgs.runCommand "krb-pwd-stash" { } ''
for srv in cn=kadmin,${DITRoot} cn=kdc,${DITRoot}
do
echo -e "${krbSrvPwd}\n${krbSrvPwd}" | \
${krb5Package}/bin/kdb5_ldap_util -r ${realm} stashsrvpw -f $out $srv 2>&1 > /dev/null
done
'';
# Password used by Kerberos services to bind to their identities
krbSrvPwd = "kerberos_service_password";
# Stash file read by Kerberos daemons containing the service password
# DO NOT DO THIS IN PRODUCTION! The stash file is a fundamental secret!
krbPwdStash = pkgs.runCommand "krb-pwd-stash" { } ''
for srv in cn=kadmin,${DITRoot} cn=kdc,${DITRoot}
do
echo -e "${krbSrvPwd}\n${krbSrvPwd}" | \
${krb5Package}/bin/kdb5_ldap_util -r ${realm} stashsrvpw -f $out $srv 2>&1 > /dev/null
done
'';
# The LDAP schema for Kerberos 5 objects is part of the source distribution of Kerberos 5
krbLdapSchema = pkgs.runCommand "krb-ldap-schema" { } ''
tar -Oxf ${krb5Package.src} \
${krb5Package.sourceRoot}/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif > $out
'';
# The LDAP schema for Kerberos 5 objects is part of the source distribution of Kerberos 5
krbLdapSchema = pkgs.runCommand "krb-ldap-schema" { } ''
tar -Oxf ${krb5Package.src} \
${krb5Package.sourceRoot}/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif > $out
'';
# Initial LDAP tree containing only the Kerberos services
ldapDIT = ''
dn: ${DITRoot}
objectClass: organization
objectClass: dcObject
dc: example
o: Example Company
# Initial LDAP tree containing only the Kerberos services
ldapDIT = ''
dn: ${DITRoot}
objectClass: organization
objectClass: dcObject
dc: example
o: Example Company
dn: cn=kdc,${DITRoot}
objectClass: krbKdcService
objectClass: simpleSecurityObject
cn: kdc
userPassword: ${krbSrvPwd}
dn: cn=kdc,${DITRoot}
objectClass: krbKdcService
objectClass: simpleSecurityObject
cn: kdc
userPassword: ${krbSrvPwd}
dn: cn=kadmin,${DITRoot}
objectClass: krbAdmService
objectClass: simpleSecurityObject
cn: kadmin
userPassword: ${krbSrvPwd}
'';
dn: cn=kadmin,${DITRoot}
objectClass: krbAdmService
objectClass: simpleSecurityObject
cn: kadmin
userPassword: ${krbSrvPwd}
'';
rootDnPwd = "ldap_root_password";
in
{
name = "kerberos_server-mit-ldap";
rootDnPwd = "ldap_root_password";
in
{
name = "kerberos_server-mit-ldap";
nodes.machine =
{ pkgs, ... }:
{
nodes.machine =
{ pkgs, ... }:
{
services.openldap = {
enable = true;
urlList = [
"ldapi:///"
"ldap://"
];
declarativeContents."${DITRoot}" = ldapDIT;
settings = {
children = {
"cn=schema".includes = [
"${pkgs.openldap}/etc/schema/core.ldif"
"${pkgs.openldap}/etc/schema/cosine.ldif"
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
"${pkgs.openldap}/etc/schema/nis.ldif"
"${krbLdapSchema}"
];
"olcDatabase={0}config" = {
attrs = {
objectClass = [ "olcDatabaseConfig" ];
olcDatabase = "{0}config";
};
};
"olcDatabase={1}mdb" = {
attrs = {
objectClass = [
"olcDatabaseConfig"
"olcMdbConfig"
];
olcDatabase = "{1}mdb";
olcDbDirectory = "/var/lib/openldap/db";
olcSuffix = DITRoot;
olcRootDN = "cn=root,${DITRoot}";
olcRootPW = rootDnPwd;
# A tiny but realistic ACL
olcAccess = [
''
to attrs=userPassword
by anonymous auth
by * none''
''
to dn.subtree="cn=${realm},cn=realms,${DITRoot}"
by dn.exact="cn=kdc,${DITRoot}" write
by dn.exact="cn=kadmin,${DITRoot}" write
by * none''
''
to *
by * read''
];
};
};
};
};
};
services.kerberos_server = {
enable = true;
settings = {
libdefaults.default_realm = realm;
realms = {
"${realm}" = {
acl = [
{
principal = "admin";
access = "all";
}
services.openldap = {
enable = true;
urlList = [
"ldapi:///"
"ldap://"
];
declarativeContents."${DITRoot}" = ldapDIT;
settings = {
children = {
"cn=schema".includes = [
"${pkgs.openldap}/etc/schema/core.ldif"
"${pkgs.openldap}/etc/schema/cosine.ldif"
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
"${pkgs.openldap}/etc/schema/nis.ldif"
"${krbLdapSchema}"
];
};
};
dbmodules = {
"${realm}" = {
db_library = "kldap";
ldap_kerberos_container_dn = "cn=realms,${DITRoot}";
ldap_kdc_dn = "cn=kdc,${DITRoot}";
ldap_kadmind_dn = "cn=kadmin,${DITRoot}";
ldap_service_password_file = toString krbPwdStash;
ldap_servers = "ldapi:///";
"olcDatabase={0}config" = {
attrs = {
objectClass = [ "olcDatabaseConfig" ];
olcDatabase = "{0}config";
};
};
"olcDatabase={1}mdb" = {
attrs = {
objectClass = [
"olcDatabaseConfig"
"olcMdbConfig"
];
olcDatabase = "{1}mdb";
olcDbDirectory = "/var/lib/openldap/db";
olcSuffix = DITRoot;
olcRootDN = "cn=root,${DITRoot}";
olcRootPW = rootDnPwd;
# A tiny but realistic ACL
olcAccess = [
''
to attrs=userPassword
by anonymous auth
by * none''
''
to dn.subtree="cn=${realm},cn=realms,${DITRoot}"
by dn.exact="cn=kdc,${DITRoot}" write
by dn.exact="cn=kadmin,${DITRoot}" write
by * none''
''
to *
by * read''
];
};
};
};
};
};
};
security.krb5 = {
enable = true;
package = krb5Package;
settings = {
libdefaults = {
default_realm = realm;
};
realms = {
"${realm}" = {
admin_server = "machine";
kdc = "machine";
services.kerberos_server = {
enable = true;
settings = {
libdefaults.default_realm = realm;
realms = {
"${realm}" = {
acl = [
{
principal = "admin";
access = "all";
}
];
};
};
dbmodules = {
"${realm}" = {
db_library = "kldap";
ldap_kerberos_container_dn = "cn=realms,${DITRoot}";
ldap_kdc_dn = "cn=kdc,${DITRoot}";
ldap_kadmind_dn = "cn=kadmin,${DITRoot}";
ldap_service_password_file = toString krbPwdStash;
ldap_servers = "ldapi:///";
};
};
};
};
security.krb5 = {
enable = true;
package = krb5Package;
settings = {
libdefaults = {
default_realm = realm;
};
realms = {
"${realm}" = {
admin_server = "machine";
kdc = "machine";
};
};
};
};
users.extraUsers.alice = {
isNormalUser = true;
};
};
users.extraUsers.alice = {
isNormalUser = true;
};
};
testScript = ''
machine.wait_for_unit("openldap.service")
testScript = ''
machine.wait_for_unit("openldap.service")
with subtest("realm container initialization"):
machine.succeed(
# Passing a master key directly avoids the need for a separate master key stash file
"kdb5_ldap_util -D cn=root,${DITRoot} create -w ${rootDnPwd} -s -P master_key",
)
with subtest("realm container initialization"):
machine.succeed(
# Passing a master key directly avoids the need for a separate master key stash file
"kdb5_ldap_util -D cn=root,${DITRoot} create -w ${rootDnPwd} -s -P master_key",
)
# These units are bound to fail, as they are started before the directory service is ready
machine.execute("systemctl restart kadmind.service kdc.service")
# These units are bound to fail, as they are started before the directory service is ready
machine.execute("systemctl restart kadmind.service kdc.service")
with subtest("service bind"):
for unit in ["kadmind", "kdc"]:
machine.wait_for_unit(f"{unit}.service")
with subtest("service bind"):
for unit in ["kadmind", "kdc"]:
machine.wait_for_unit(f"{unit}.service")
with subtest("administration principal initialization"):
machine.succeed("kadmin.local add_principal -pw admin_pw admin")
with subtest("administration principal initialization"):
machine.succeed("kadmin.local add_principal -pw admin_pw admin")
with subtest("user principal creation and kinit"):
machine.succeed(
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
"echo alice_pw | sudo -u alice kinit",
)
# Make extra sure that the user principal actually exists in the directory
machine.succeed(
"ldapsearch -x -D cn=root,${DITRoot} -w ${rootDnPwd} \
-b ${DITRoot} 'krbPrincipalName=alice@${realm}' | grep 'numEntries: 1'"
)
'';
with subtest("user principal creation and kinit"):
machine.succeed(
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
"echo alice_pw | sudo -u alice kinit",
)
# Make extra sure that the user principal actually exists in the directory
machine.succeed(
"ldapsearch -x -D cn=root,${DITRoot} -w ${rootDnPwd} \
-b ${DITRoot} 'krbPrincipalName=alice@${realm}' | grep 'numEntries: 1'"
)
'';
meta.maintainers = [ pkgs.lib.maintainers.nessdoor ];
}
meta.maintainers = [ pkgs.lib.maintainers.nessdoor ];
}
)

View File

@@ -1,64 +1,66 @@
{ pkgs, ... }:
{
name = "kerberos_server-mit";
import ../make-test-python.nix (
{ pkgs, ... }:
{
name = "kerberos_server-mit";
nodes.machine =
{
config,
libs,
pkgs,
...
}:
{
services.kerberos_server = {
enable = true;
settings.realms = {
"FOO.BAR".acl = [
{
principal = "admin";
access = [
"add"
"cpw"
];
}
];
};
};
security.krb5 = {
enable = true;
package = pkgs.krb5;
settings = {
libdefaults = {
default_realm = "FOO.BAR";
nodes.machine =
{
config,
libs,
pkgs,
...
}:
{
services.kerberos_server = {
enable = true;
settings.realms = {
"FOO.BAR".acl = [
{
principal = "admin";
access = [
"add"
"cpw"
];
}
];
};
realms = {
"FOO.BAR" = {
admin_server = "machine";
kdc = "machine";
};
security.krb5 = {
enable = true;
package = pkgs.krb5;
settings = {
libdefaults = {
default_realm = "FOO.BAR";
};
realms = {
"FOO.BAR" = {
admin_server = "machine";
kdc = "machine";
};
};
};
};
users.extraUsers.alice = {
isNormalUser = true;
};
};
users.extraUsers.alice = {
isNormalUser = true;
};
};
testScript = ''
machine.succeed(
"kdb5_util create -s -r FOO.BAR -P master_key",
"systemctl restart kadmind.service kdc.service",
)
testScript = ''
machine.succeed(
"kdb5_util create -s -r FOO.BAR -P master_key",
"systemctl restart kadmind.service kdc.service",
)
for unit in ["kadmind", "kdc"]:
machine.wait_for_unit(f"{unit}.service")
for unit in ["kadmind", "kdc"]:
machine.wait_for_unit(f"{unit}.service")
machine.succeed(
"kadmin.local add_principal -pw admin_pw admin",
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
"echo alice_pw | sudo -u alice kinit",
)
'';
machine.succeed(
"kadmin.local add_principal -pw admin_pw admin",
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
"echo alice_pw | sudo -u alice kinit",
)
'';
meta.maintainers = [ pkgs.lib.maintainers.dblsaiko ];
}
meta.maintainers = [ pkgs.lib.maintainers.dblsaiko ];
}
)

View File

@@ -44,11 +44,6 @@
};
testScript = ''
def with_unit_path(node, cmd):
"""Run cmd with the PATH systemd hands to komodo-periphery.service."""
unit_path = "$(systemctl show -p Environment --value komodo-periphery | grep -o 'PATH=[^ ]*' | cut -d= -f2)"
node.succeed(f"export PATH={unit_path}; {cmd}")
start_all()
with subtest("Inbound periphery starts and serves /version"):
@@ -64,15 +59,9 @@
periphery.succeed("test -d /var/lib/komodo-periphery/keys")
periphery.succeed("test -d /var/lib/komodo-periphery/ssl")
with subtest("Service PATH provides docker, docker compose and git"):
with_unit_path(periphery, "command -v docker && command -v git && docker compose version")
with subtest("Outbound periphery stays active despite unreachable core"):
peripheryOutbound.wait_for_unit("komodo-periphery.service")
peripheryOutbound.sleep(15)
peripheryOutbound.succeed("systemctl is-active komodo-periphery")
with subtest("Terminal-enabled periphery sees system-wide tools on PATH"):
with_unit_path(peripheryOutbound, "command -v bash")
'';
}

View File

@@ -1,5 +1,6 @@
{
runTest,
...
}:
{
additionalFiles = runTest ./additional-files.nix;

File diff suppressed because it is too large Load Diff

View File

@@ -401,6 +401,17 @@ let
driver = "nl80211";
pkcs11 = {
enable = true;
package = pkgs.libp11.overrideAttrs {
# TODO: Remove this override once a libp11 release includes the fix for
# https://github.com/OpenSC/libp11/issues/672
version = "0.4.21-unstable-2026-08-19";
src = pkgs.fetchFromGitHub {
owner = "OpenSC";
repo = "libp11";
rev = "e72a2014eb078c7b784e2a9be3e7abd3dce8fd5a";
hash = "sha256-V9ZRPUJp2FkK+Zb/qYC13SDE7+oyJ/hlnO/XEN2zDD8=";
};
};
};
};
};

View File

@@ -1,4 +1,4 @@
{ pkgs, runTest }:
{ pkgs, runTest, ... }:
let
hosts = ''
192.168.2.101 acme.test

View File

@@ -1,4 +1,4 @@
{ runTest }:
{ pkgs, runTest, ... }:
builtins.listToAttrs (
map
(packageName: {

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