Compare commits

...
36 Commits
Author SHA1 Message Date
Richie fb58bac89d refactor(signal): replace Apprise with httpx
treefmt / nix fmt (pull_request) Successful in 3s
build_systems / build-portal-1 (pull_request) Successful in 22s
build_systems / build-bob (pull_request) Successful in 45s
build_systems / build-brain (pull_request) Successful in 48s
build_systems / build-jeeves (pull_request) Successful in 50s
build_systems / build-rhapsody-in-green (pull_request) Successful in 55s
test ebook search / test-ebook-search (pull_request) Successful in 1m7s
treefmt / nix fmt (push) Successful in 2s
build_systems / build-portal-1 (push) Successful in 17s
build_systems / build-bob (push) Successful in 29s
build_systems / build-brain (push) Successful in 29s
build_systems / build-jeeves (push) Successful in 34s
build_systems / build-rhapsody-in-green (push) Successful in 38s
test ebook search / test-ebook-search (push) Successful in 1m6s
2026-09-19 22:40:45 -04:00
Richie 78b8ae2874 bugfix adding-ruff-to-nix-builders
treefmt / nix fmt (pull_request) Failing after 3s
treefmt / nix fmt (push) Failing after 3s
build_systems / build-portal-1 (pull_request) Successful in 33s
build_systems / build-portal-1 (push) Successful in 28s
build_systems / build-brain (pull_request) Successful in 59s
build_systems / build-bob (pull_request) Successful in 1m2s
build_systems / build-bob (push) Successful in 55s
build_systems / build-brain (push) Successful in 57s
build_systems / build-rhapsody-in-green (push) Successful in 1m5s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m17s
test ebook search / test-ebook-search (pull_request) Successful in 1m16s
test ebook search / test-ebook-search (push) Successful in 1m15s
build_systems / build-jeeves (pull_request) Successful in 1m25s
build_systems / build-jeeves (push) Successful in 1m20s
2026-09-19 22:36:06 -04:00
Richie e18cb7b963 chore: drop Python dependency declarations
treefmt / nix fmt (pull_request) Successful in 4s
build_systems / build-portal-1 (pull_request) Successful in 34s
build_systems / build-bob (pull_request) Successful in 53s
build_systems / build-brain (pull_request) Successful in 54s
test ebook search / test-ebook-search (pull_request) Successful in 1m11s
build_systems / build-jeeves (pull_request) Successful in 1m27s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m37s
treefmt / nix fmt (push) Successful in 2s
build_systems / build-portal-1 (push) Successful in 18s
build_systems / build-brain (push) Successful in 29s
build_systems / build-bob (push) Successful in 29s
build_systems / build-jeeves (push) Successful in 33s
build_systems / build-rhapsody-in-green (push) Successful in 39s
test ebook search / test-ebook-search (push) Successful in 1m6s
2026-09-19 21:08:15 -04:00
Richie ac4746277d test(services): run tests during system builds 2026-09-19 21:05:41 -04:00
Richie e2c240ba4b refactor(python): use dedicated runtime environments 2026-09-19 21:01:23 -04:00
Richie 545115725c refactor(jeeves): remove startup validation 2026-09-19 20:51:49 -04:00
Richie 9dbb8f69a8 deleted dead file 2026-09-19 20:47:14 -04:00
Richie 3614428e3d (feat)removing firefox
treefmt / nix fmt (pull_request) Successful in 4s
build_systems / build-portal-1 (pull_request) Successful in 31s
build_systems / build-brain (pull_request) Successful in 53s
build_systems / build-bob (pull_request) Successful in 54s
build_systems / build-jeeves (pull_request) Successful in 58s
pytest / pytest (pull_request) Successful in 1m6s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m12s
test ebook search / test-ebook-search (pull_request) Successful in 1m18s
treefmt / nix fmt (push) Successful in 4s
build_systems / build-jeeves (push) Successful in 7s
build_systems / build-portal-1 (push) Successful in 19s
build_systems / build-brain (push) Successful in 28s
build_systems / build-bob (push) Successful in 31s
build_systems / build-rhapsody-in-green (push) Successful in 40s
pytest / pytest (push) Successful in 53s
test ebook search / test-ebook-search (push) Successful in 1m15s
im not using firefox any more and with the move to x86 v3 1 less browser build is nice
2026-09-18 09:38:53 -04:00
Richie 7cc87ff278 more x86-64-v3 workarounds and text exclushions
treefmt / nix fmt (pull_request) Successful in 4s
test ebook search / test-ebook-search (pull_request) Successful in 1m5s
pytest / pytest (pull_request) Successful in 48s
build_systems / build-portal-1 (pull_request) Successful in 18s
build_systems / build-brain (pull_request) Successful in 26s
build_systems / build-bob (pull_request) Successful in 27s
build_systems / build-jeeves (pull_request) Successful in 31s
build_systems / build-rhapsody-in-green (pull_request) Successful in 38s
treefmt / nix fmt (push) Successful in 3s
build_systems / build-portal-1 (push) Successful in 21s
build_systems / build-brain (push) Successful in 31s
build_systems / build-bob (push) Successful in 33s
build_systems / build-jeeves (push) Successful in 38s
build_systems / build-rhapsody-in-green (push) Successful in 47s
pytest / pytest (push) Successful in 56s
test ebook search / test-ebook-search (push) Successful in 1m14s
2026-09-17 08:44:18 -04:00
Richie 224c75768b moved modbus to extraComponents
modbus intgration requres more then just pymodbus bus now
2026-09-17 08:35:35 -04:00
Richie 562c92ae77 more test issues 2026-09-17 08:35:35 -04:00
Richie dd4a0e1f9c more test-exclusions 2026-09-17 08:35:35 -04:00
Richie c56aa0ab3d fix(overlays): stabilize timing-sensitive tests 2026-09-17 08:35:35 -04:00
Richie 21066116b0 testing numprocesses to fix pytest-xdist tests 2026-09-17 08:35:35 -04:00
Richie 0b333552e6 fix(overlays): exclude failing x86-64-v3 tests
Skip the flaky GnuTLS UDP readiness test and the SciPy FFT tests whose
precision differences are acceptable for our workloads.
2026-09-17 08:35:35 -04:00
Richie b1c21438d9 removed hostPlatform from portal-1 2026-09-17 08:35:35 -04:00
Richie 0f794411fd testing x86_v3 2026-09-17 08:35:35 -04:00
Richie f9049353e2 removing open_webui
treefmt / nix fmt (pull_request) Successful in 4s
build_systems / build-portal-1 (pull_request) Successful in 27s
build_systems / build-brain (pull_request) Successful in 48s
build_systems / build-bob (pull_request) Successful in 52s
build_systems / build-jeeves (pull_request) Successful in 53s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m4s
pytest / pytest (pull_request) Successful in 1m17s
test ebook search / test-ebook-search (pull_request) Successful in 1m21s
build_systems / build-brain (push) Successful in 34s
build_systems / build-jeeves (push) Successful in 44s
build_systems / build-rhapsody-in-green (push) Successful in 50s
pytest / pytest (push) Successful in 1m1s
treefmt / nix fmt (push) Successful in 2s
build_systems / build-portal-1 (push) Successful in 22s
build_systems / build-bob (push) Successful in 38s
test ebook search / test-ebook-search (push) Successful in 1m15s
2026-09-16 20:26:47 -04:00
Richie f905b6e270 removing camofox-browser.nix
treefmt / nix fmt (pull_request) Successful in 4s
build_systems / build-portal-1 (pull_request) Successful in 36s
build_systems / build-brain (pull_request) Successful in 1m6s
pytest / pytest (pull_request) Successful in 1m8s
build_systems / build-bob (pull_request) Successful in 1m12s
test ebook search / test-ebook-search (pull_request) Successful in 1m23s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m30s
build_systems / build-jeeves (pull_request) Successful in 1m32s
treefmt / nix fmt (push) Successful in 3s
build_systems / build-portal-1 (push) Successful in 33s
build_systems / build-brain (push) Successful in 52s
build_systems / build-bob (push) Successful in 57s
build_systems / build-jeeves (push) Successful in 1m5s
pytest / pytest (push) Successful in 1m16s
build_systems / build-rhapsody-in-green (push) Successful in 1m20s
test ebook search / test-ebook-search (push) Successful in 1m23s
2026-09-13 12:32:35 -04:00
Richie f1f027abfe removed steve
pytest / pytest (push) Successful in 1m17s
build_systems / build-brain (pull_request) Successful in 1m7s
pytest / pytest (pull_request) Successful in 1m6s
build_systems / build-bob (pull_request) Successful in 1m37s
test ebook search / test-ebook-search (pull_request) Successful in 1m22s
build_systems / build-portal-1 (pull_request) Successful in 37s
treefmt / nix fmt (pull_request) Successful in 4s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m46s
build_systems / build-jeeves (pull_request) Successful in 1m52s
treefmt / nix fmt (push) Successful in 5s
build_systems / build-portal-1 (push) Successful in 40s
build_systems / build-brain (push) Successful in 1m0s
build_systems / build-bob (push) Successful in 1m9s
test ebook search / test-ebook-search (push) Successful in 1m17s
build_systems / build-jeeves (push) Successful in 1m43s
build_systems / build-rhapsody-in-green (push) Successful in 1m38s
2026-09-12 11:20:15 -04:00
Richie 0243da86f2 refactor(home): trim user packages and move GUI modules into Richie's config 2026-09-12 11:20:15 -04:00
Richie 1803da420e feat(jeeves): limit builder CPU usage and tune Nix parallelism
treefmt / nix fmt (pull_request) Successful in 5s
pytest / pytest (pull_request) Successful in 57s
build_systems / build-portal-1 (pull_request) Successful in 1m4s
test ebook search / test-ebook-search (pull_request) Successful in 1m11s
build_systems / build-brain (pull_request) Successful in 1m49s
build_systems / build-bob (pull_request) Successful in 1m52s
build_systems / build-rhapsody-in-green (pull_request) Successful in 2m14s
build_systems / build-jeeves (pull_request) Successful in 2m32s
treefmt / nix fmt (push) Successful in 4s
build_systems / build-jeeves (push) Successful in 8s
build_systems / build-portal-1 (push) Successful in 18s
build_systems / build-brain (push) Successful in 30s
build_systems / build-bob (push) Successful in 34s
build_systems / build-rhapsody-in-green (push) Successful in 45s
pytest / pytest (push) Successful in 54s
test ebook search / test-ebook-search (push) Successful in 1m10s
2026-09-12 09:47:35 -04:00
Richie 2fb3a0d3ba feat(gitea): allow 12-hour runner builds
treefmt / nix fmt (pull_request) Successful in 4s
pytest / pytest (pull_request) Successful in 1m12s
treefmt / nix fmt (push) Successful in 5s
test ebook search / test-ebook-search (pull_request) Successful in 1m34s
build_systems / build-portal-1 (pull_request) Successful in 1m38s
build_systems / build-portal-1 (push) Successful in 38s
build_systems / build-brain (pull_request) Successful in 2m7s
pytest / pytest (push) Successful in 46s
build_systems / build-bob (pull_request) Successful in 2m9s
build_systems / build-brain (push) Successful in 51s
build_systems / build-bob (push) Successful in 56s
test ebook search / test-ebook-search (push) Successful in 54s
build_systems / build-rhapsody-in-green (pull_request) Successful in 2m18s
build_systems / build-rhapsody-in-green (push) Successful in 1m7s
build_systems / build-jeeves (pull_request) Successful in 2m40s
build_systems / build-jeeves (push) Successful in 1m23s
2026-09-12 09:09:30 -04:00
Richie 4154640637 feat(jeeves): move container state to dedicated ZFS dataset
treefmt / nix fmt (pull_request) Successful in 4s
pytest / pytest (pull_request) Successful in 1m30s
test ebook search / test-ebook-search (pull_request) Successful in 1m28s
build_systems / build-portal-1 (pull_request) Successful in 2m51s
build_systems / build-bob (pull_request) Successful in 3m43s
build_systems / build-jeeves (pull_request) Successful in 3m43s
build_systems / build-brain (pull_request) Successful in 3m29s
build_systems / build-rhapsody-in-green (pull_request) Successful in 3m54s
treefmt / nix fmt (push) Successful in 4s
build_systems / build-portal-1 (push) Successful in 24s
pytest / pytest (push) Successful in 33s
build_systems / build-brain (push) Successful in 41s
test ebook search / test-ebook-search (push) Successful in 38s
build_systems / build-bob (push) Successful in 46s
build_systems / build-jeeves (push) Successful in 1m2s
build_systems / build-rhapsody-in-green (push) Successful in 1m5s
- add a performance-tuned media/containers dataset
- store Docker and NixOS container state on the dataset
- prepare storage directories after ZFS mounts
- bind NixOS container state to its required path
- configure snapshot retention for container storage
2026-09-11 14:58:41 -04:00
Richie 78641f78dd updating snapshot config
treefmt / nix fmt (pull_request) Successful in 6s
pytest / pytest (pull_request) Successful in 1m2s
test ebook search / test-ebook-search (pull_request) Successful in 1m10s
build_systems / build-portal-1 (pull_request) Successful in 1m15s
build_systems / build-brain (pull_request) Successful in 2m5s
build_systems / build-bob (pull_request) Successful in 2m10s
build_systems / build-jeeves (pull_request) Successful in 2m32s
build_systems / build-rhapsody-in-green (pull_request) Successful in 2m34s
treefmt / nix fmt (push) Successful in 6s
build_systems / build-jeeves (push) Successful in 17s
build_systems / build-rhapsody-in-green (push) Successful in 23s
build_systems / build-portal-1 (push) Successful in 39s
pytest / pytest (push) Successful in 51s
build_systems / build-brain (push) Successful in 57s
test ebook search / test-ebook-search (push) Successful in 59s
build_systems / build-bob (push) Successful in 1m1s
2026-09-11 12:37:47 -04:00
Richie 0e09b1db34 feat(zfs): mount dedicated Nix build dataset
treefmt / nix fmt (pull_request) Successful in 4s
build_systems / build-portal-1 (pull_request) Successful in 33s
pytest / pytest (pull_request) Successful in 34s
test ebook search / test-ebook-search (pull_request) Successful in 39s
build_systems / build-brain (pull_request) Successful in 59s
build_systems / build-jeeves (pull_request) Successful in 1m16s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m16s
build_systems / build-bob (pull_request) Successful in 1m4s
treefmt / nix fmt (push) Successful in 5s
build_systems / build-rhapsody-in-green (push) Successful in 18s
build_systems / build-portal-1 (push) Successful in 49s
pytest / pytest (push) Successful in 1m1s
test ebook search / test-ebook-search (push) Successful in 1m18s
build_systems / build-bob (push) Successful in 1m33s
build_systems / build-brain (push) Successful in 1m46s
build_systems / build-jeeves (push) Successful in 2m30s
Mount root_pool/nix_build at /nix/var/nix/builds on existing hosts and
generate the same layout for new installations.
2026-09-11 12:07:24 -04:00
Richie 82a3bdf562 temp v3 suport 2026-09-11 12:00:43 -04:00
Richie 46cb80f809 feat(installer) adding root_pool/nix_build 2026-09-11 10:47:52 -04:00
Richie bce4ccb754 config(docker): disable live restore
treefmt / nix fmt (pull_request) Successful in 7s
pytest / pytest (pull_request) Successful in 1m40s
test ebook search / test-ebook-search (pull_request) Successful in 1m40s
build_systems / build-portal-1 (pull_request) Successful in 2m40s
build_systems / build-brain (pull_request) Successful in 3m43s
build_systems / build-bob (pull_request) Successful in 4m0s
build_systems / build-rhapsody-in-green (pull_request) Successful in 4m19s
build_systems / build-jeeves (pull_request) Successful in 4m37s
treefmt / nix fmt (push) Successful in 3s
build_systems / build-portal-1 (push) Successful in 22s
pytest / pytest (push) Successful in 31s
test ebook search / test-ebook-search (push) Successful in 32s
build_systems / build-brain (push) Successful in 35s
build_systems / build-bob (push) Successful in 39s
build_systems / build-rhapsody-in-green (push) Successful in 48s
build_systems / build-jeeves (push) Successful in 52s
2026-09-10 07:26:34 -04:00
Richie 7c7740fe90 remove dov
treefmt / nix fmt (pull_request) Successful in 6s
pytest / pytest (pull_request) Successful in 57s
test ebook search / test-ebook-search (pull_request) Successful in 1m1s
build_systems / build-portal-1 (pull_request) Successful in 1m7s
build_systems / build-brain (pull_request) Successful in 1m25s
build_systems / build-bob (pull_request) Successful in 1m26s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m33s
build_systems / build-jeeves (pull_request) Successful in 1m45s
treefmt / nix fmt (push) Successful in 4s
build_systems / build-jeeves (push) Successful in 7s
build_systems / build-portal-1 (push) Successful in 24s
test ebook search / test-ebook-search (push) Successful in 31s
pytest / pytest (push) Successful in 32s
build_systems / build-brain (push) Successful in 35s
build_systems / build-bob (push) Successful in 38s
build_systems / build-rhapsody-in-green (push) Successful in 50s
2026-09-09 11:06:44 -04:00
Richie a59ccd293d feat(jeeves): enable x86-64 v2 and v3 system features
treefmt / nix fmt (pull_request) Successful in 6s
build_systems / build-portal-1 (pull_request) Successful in 31s
pytest / pytest (pull_request) Successful in 33s
test ebook search / test-ebook-search (pull_request) Successful in 36s
build_systems / build-brain (pull_request) Successful in 53s
build_systems / build-bob (pull_request) Successful in 53s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m5s
build_systems / build-jeeves (pull_request) Successful in 1m8s
treefmt / nix fmt (push) Successful in 5s
build_systems / build-jeeves (push) Successful in 10s
build_systems / build-portal-1 (push) Successful in 22s
pytest / pytest (push) Successful in 32s
test ebook search / test-ebook-search (push) Successful in 34s
build_systems / build-bob (push) Successful in 41s
build_systems / build-brain (push) Successful in 36s
build_systems / build-rhapsody-in-green (push) Successful in 51s
2026-09-08 19:59:14 -04:00
Richie 5514047eda feat(jeeves): share one system closure across builders
treefmt / nix fmt (pull_request) Successful in 5s
build_systems / build-portal-1 (pull_request) Successful in 32s
pytest / pytest (pull_request) Successful in 32s
test ebook search / test-ebook-search (pull_request) Successful in 36s
build_systems / build-brain (pull_request) Successful in 54s
build_systems / build-bob (pull_request) Successful in 55s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m6s
build_systems / build-jeeves (pull_request) Successful in 1m58s
treefmt / nix fmt (push) Successful in 5s
build_systems / build-portal-1 (push) Successful in 24s
pytest / pytest (push) Successful in 32s
build_systems / build-brain (push) Successful in 37s
test ebook search / test-ebook-search (push) Successful in 35s
build_systems / build-bob (push) Successful in 41s
build_systems / build-rhapsody-in-green (push) Successful in 50s
build_systems / build-jeeves (push) Successful in 53s
Reuse a single NixOS container build for all runners while preserving
unique runtime hostnames and existing Gitea registrations.
2026-09-08 19:37:18 -04:00
Richie 810f9a66f6 flake update 09-08-26
treefmt / nix fmt (pull_request) Successful in 5s
build_systems / build-portal-1 (pull_request) Successful in 30s
pytest / pytest (pull_request) Successful in 32s
test ebook search / test-ebook-search (pull_request) Successful in 37s
build_systems / build-brain (pull_request) Successful in 49s
build_systems / build-bob (pull_request) Successful in 55s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m6s
build_systems / build-jeeves (pull_request) Successful in 2m33s
treefmt / nix fmt (push) Successful in 5s
build_systems / build-portal-1 (push) Successful in 24s
pytest / pytest (push) Successful in 32s
build_systems / build-brain (push) Successful in 38s
test ebook search / test-ebook-search (push) Successful in 36s
build_systems / build-bob (push) Successful in 41s
build_systems / build-rhapsody-in-green (push) Successful in 52s
build_systems / build-jeeves (push) Successful in 2m9s
2026-09-08 19:26:26 -04:00
Richie 3aa66c48af removing zerotierone from jeeves
treefmt / nix fmt (pull_request) Successful in 6s
pytest / pytest (pull_request) Successful in 39s
build_systems / build-portal-1 (pull_request) Successful in 45s
test ebook search / test-ebook-search (pull_request) Successful in 46s
build_systems / build-brain (pull_request) Successful in 1m1s
build_systems / build-bob (pull_request) Successful in 1m1s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m10s
build_systems / build-jeeves (pull_request) Successful in 2m29s
treefmt / nix fmt (push) Successful in 5s
build_systems / build-portal-1 (push) Successful in 24s
pytest / pytest (push) Successful in 32s
build_systems / build-brain (push) Successful in 37s
build_systems / build-bob (push) Successful in 37s
test ebook search / test-ebook-search (push) Successful in 37s
build_systems / build-rhapsody-in-green (push) Successful in 50s
build_systems / build-jeeves (push) Successful in 2m2s
2026-09-08 18:12:20 -04:00
Richie 97d63eecda add portal-1 to build_system
treefmt / nix fmt (pull_request) Successful in 6s
pytest / pytest (pull_request) Successful in 35s
test ebook search / test-ebook-search (pull_request) Successful in 41s
build_systems / build-portal-1 (pull_request) Successful in 57s
build_systems / build-brain (pull_request) Successful in 57s
build_systems / build-bob (pull_request) Successful in 59s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m12s
build_systems / build-jeeves (pull_request) Successful in 2m29s
treefmt / nix fmt (push) Successful in 6s
build_systems / build-portal-1 (push) Successful in 26s
pytest / pytest (push) Successful in 34s
test ebook search / test-ebook-search (push) Successful in 35s
build_systems / build-brain (push) Successful in 39s
build_systems / build-bob (push) Successful in 39s
build_systems / build-rhapsody-in-green (push) Successful in 58s
build_systems / build-jeeves (push) Successful in 2m21s
2026-09-08 16:40:45 -04:00
Richie 1d0ced8fd4 removed pirate-weather from home_assistant
test ebook search / test-ebook-search (push) Successful in 45s
treefmt / nix fmt (pull_request) Successful in 6s
treefmt / nix fmt (push) Successful in 6s
pytest / pytest (pull_request) Successful in 35s
test ebook search / test-ebook-search (pull_request) Successful in 47s
pytest / pytest (push) Successful in 42s
build_systems / build-brain (pull_request) Successful in 59s
build_systems / build-bob (push) Successful in 58s
build_systems / build-bob (pull_request) Successful in 1m1s
build_systems / build-brain (push) Successful in 55s
build_systems / build-rhapsody-in-green (pull_request) Successful in 1m15s
build_systems / build-rhapsody-in-green (push) Successful in 1m10s
build_systems / build-jeeves (pull_request) Successful in 2m52s
build_systems / build-jeeves (push) Successful in 2m50s
2026-09-08 16:38:21 -04:00
82 changed files with 714 additions and 1556 deletions
+1
View File
@@ -18,6 +18,7 @@ jobs:
- "brain"
- "jeeves"
- "rhapsody-in-green"
- "portal-1"
continue-on-error: true
steps:
- uses: actions/checkout@v4
@@ -15,7 +15,6 @@ jobs:
steps:
- name: merge_flake_lock_update
run: >-
nix develop .#devShells.x86_64-linux.default -c
python -m python.gitea_flake_lock merge
--repo "${{ github.repository }}"
env:
-19
View File
@@ -1,19 +0,0 @@
name: pytest
on:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
pytest:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Run tests
run: nix develop .#devShells.x86_64-linux.default -c pytest tests
-1
View File
@@ -21,6 +21,5 @@ jobs:
JEEVES_BOT_TOKEN: ${{ secrets.JEEVES_BOT_TOKEN }}
GITEA_URL: https://gitea.tmmworkshop.com
run: >-
nix develop .#devShells.x86_64-linux.default -c
python -m python.gitea_flake_lock update
--repo "${{ github.repository }}"
-2
View File
@@ -336,8 +336,6 @@
"yubioath",
"yzhang",
"zeroconf",
"zerotier",
"zerotierone",
"zoxide",
"zram",
"zstd"
+4
View File
@@ -31,6 +31,10 @@ in
"flakes"
"ca-derivations"
];
system-features = lib.mkAfter [
"gccarch-x86-64-v2"
"gccarch-x86-64-v3"
];
warn-dirty = false;
flake-registry = ""; # disable global flake registries
connect-timeout = 10;
-1
View File
@@ -2,6 +2,5 @@
{
environment.systemPackages = with pkgs; [
git
my_python
];
}
+1
View File
@@ -17,6 +17,7 @@
logDriver = "local";
storageDriver = "overlay2";
daemon.settings = {
live-restore = false;
experimental = true;
exec-opts = [ "native.cgroupdriver=systemd" ];
log-opts = {
+9
View File
@@ -0,0 +1,9 @@
{
nixpkgs.hostPlatform = {
system = "x86_64-linux";
gcc = {
arch = "x86-64-v3";
tune = "generic";
};
};
}
+42 -1
View File
@@ -1,4 +1,5 @@
{
inputs,
pkgs,
lib,
config,
@@ -6,6 +7,11 @@
}:
let
cfg = config.services.snapshot_manager;
snapshotManagerPackages =
ps: with ps; [
httpx
typer
];
in
{
options = {
@@ -34,6 +40,41 @@ in
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: _prev: {
snapshot_manager_python = final.python314.withPackages snapshotManagerPackages;
snapshot_manager_test_python = final.python314.withPackages (
ps:
snapshotManagerPackages ps
++ (with ps; [
pyfakefs
pytest
pytest-asyncio
pytest-mock
pytest-xdist
])
);
snapshot_manager_tests =
final.runCommand "snapshot-manager-tests"
{
nativeBuildInputs = [ final.snapshot_manager_test_python ];
}
''
export HOME="$TMPDIR"
cd ${inputs.self}
pytest \
-o cache_dir="$TMPDIR/pytest-cache" \
tests/test_common.py \
tests/test_signal_alert.py \
tests/test_snapshot_manager.py \
tests/test_zfs.py
touch "$out"
'';
})
];
system.checks = [ pkgs.snapshot_manager_tests ];
systemd = {
services.snapshot_manager = {
description = "ZFS Snapshot Manager";
@@ -45,7 +86,7 @@ in
};
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.my_python}/bin/python -m python.tools.snapshot_manager ${lib.escapeShellArg cfg.path}";
ExecStart = "${pkgs.snapshot_manager_python}/bin/python -m python.tools.snapshot_manager ${lib.escapeShellArg cfg.path}";
}
// lib.optionalAttrs (cfg.EnvironmentFile != null) {
EnvironmentFile = cfg.EnvironmentFile;
+6
View File
@@ -22,6 +22,12 @@ hourly = 0
daily = 0
monthly = 0
["root_pool/nix_build"]
15_min = 1
hourly = 0
daily = 0
monthly = 0
["root_pool/var"]
15_min = 8
hourly = 24
Generated
+15 -38
View File
@@ -20,28 +20,6 @@
"type": "github"
}
},
"firefox-addons": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"dir": "pkgs/firefox-addons",
"lastModified": 1787025780,
"narHash": "sha256-NhyLP9G4DFOn/7aYr7K/D7hWrzEGr5EgUBV+lpdmJ24=",
"owner": "rycee",
"repo": "nur-expressions",
"rev": "5ad360b6d3cb0aa1b61f9cb27fef113ca9117c37",
"type": "gitlab"
},
"original": {
"dir": "pkgs/firefox-addons",
"owner": "rycee",
"repo": "nur-expressions",
"type": "gitlab"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@@ -49,11 +27,11 @@
]
},
"locked": {
"lastModified": 1786999651,
"narHash": "sha256-MTGMFlLDTklsXhCp4r5GXB4VAVadPdalXLvUjd/K7h0=",
"lastModified": 1788651960,
"narHash": "sha256-v9wJd32eZ2bvhBzVOd7TIjLQd011P7nwOhjKtWlci5I=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "353742587cbaf079b3caee743115d037bc51fea6",
"rev": "2c0350c759688177331b8f5242311fae8877bdb3",
"type": "github"
},
"original": {
@@ -67,11 +45,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1786867632,
"narHash": "sha256-ez+ubZlA1RtdjCB18a6zJ9M4u8qoPDy08EcnsW5M3Xw=",
"lastModified": 1788860136,
"narHash": "sha256-MhPMOFV4pVkygWEbQ8t1De/uQ9cWF1u++tRe2L5tG48=",
"owner": "nixos",
"repo": "nixos-hardware",
"rev": "ff17823245ab9ff7bcae6acf950bd89cba82c38c",
"rev": "62173785b9a18c78b4a15aca2623d02bceb9d077",
"type": "github"
},
"original": {
@@ -96,11 +74,11 @@
},
"nixpkgs-master": {
"locked": {
"lastModified": 1787081018,
"narHash": "sha256-K0uwZBtZsbBigHAMQW7YWti3gPe6a5ct5bcOw5F+Q9Y=",
"lastModified": 1788892992,
"narHash": "sha256-cIMFh9gyU4/aLeB3JCcsWM3tTAvD9pAq9Smr1Wa8aIU=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "cacac5ac351a010599d9f9d106acfed25a8e4c77",
"rev": "dff6994123e257ec9901c271bc2b52e64d7c8f05",
"type": "github"
},
"original": {
@@ -128,11 +106,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1787001381,
"narHash": "sha256-Ue1Yo8gfHdD4TMtNewhA4tkSYeFqXThju0nCyJc3ALo=",
"lastModified": 1788752844,
"narHash": "sha256-VaWGJ6+cIYN2erfSecbRV+4ljI185Ty2wUrXyvQbgOw=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "ec2d622de0773551768cf98f3fc50cbcc003b9c5",
"rev": "dc5d91f840324650bac8c379428c7037a416959a",
"type": "github"
},
"original": {
@@ -145,7 +123,6 @@
"root": {
"inputs": {
"disko": "disko",
"firefox-addons": "firefox-addons",
"home-manager": "home-manager",
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_2",
@@ -162,11 +139,11 @@
]
},
"locked": {
"lastModified": 1786629091,
"narHash": "sha256-gkig4nPi1CWc4Z50GBsjE4ygSE7hMpl/TwID2an2Cck=",
"lastModified": 1788337237,
"narHash": "sha256-gkSH8VUtCo6hnysNmb9DbTuDepH2t5pv+QWjP75xKAk=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "a8627b21b9107c5711c96b84f32a9a4b3d45295f",
"rev": "fbf759290e0cb0a98dfc813a4eb7d53ad1dacb57",
"type": "github"
},
"original": {
-5
View File
@@ -26,11 +26,6 @@
inputs.nixpkgs.follows = "nixpkgs";
};
firefox-addons = {
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
+2 -30
View File
@@ -15,34 +15,6 @@
};
};
python-env = final: _prev: {
my_python = final.python314.withPackages (
ps: with ps; [
alembic
apprise
fastapi
fastapi-cli
httpx
jinja2
mypy
pgvector
psycopg
pydantic
pyfakefs
pytest
pytest-cov
pytest-mock
pytest-xdist
python-multipart
pydantic-settings
ruff
sqlalchemy
tenacity
tinytuya
typer
uvicorn
websockets
]
);
};
test-exclusions = import ./test-exclusions.nix;
x86-64-v3-workarounds = import ./x86-64-v3-workarounds.nix;
}
+133
View File
@@ -0,0 +1,133 @@
# Test exclusions for the locally rebuilt x86-64-v3 package set.
#
# Selecting x86-64-v3 changes every affected derivation, so the normal
# nixpkgs binary cache cannot be used and upstream test suites run locally.
# The jeeves builder uses /tmp/nix-builds so filesystem tests run on tmpfs
# instead of ZFS with normalization=formD and utf8only=on; those tests remain
# enabled. The remaining workarounds cover UDP readiness, resource-sensitive
# parser and nested-worker races, and mismatched timeout clocks, plus
# architecture-dependent floating-point differences whose risk we accept for
# our workloads. Keep these exceptions visible until their causes are fixed.
_final: prev: {
gnutls = prev.gnutls.overrideAttrs (old: {
# This test uses a fixed four-second sleep instead of checking UDP
# readiness; the client saw no listener in the x86-64-v3 build.
postPatch = (old.postPatch or "") + ''
sed '2iexit 77' -i tests/serv-udp.sh
'';
});
prometheus = prev.prometheus.overrideAttrs (
old:
let
assets = old.passthru.assets.overrideAttrs (assetsOld: {
# CodeMirror's bounded synchronous parser can return an incomplete tree
# when these cases run on a heavily loaded builder.
postPatch = (assetsOld.postPatch or "") + ''
substituteInPlace module/codemirror-promql/src/complete/hybrid.test.ts \
--replace-fail "it(value.title, () => {" \
"(value.title === 'autocomplete topk params 2' ? it.skip : it)(value.title, () => {"
substituteInPlace module/codemirror-promql/src/parser/vector.test.ts \
--replace-fail "it(value.binaryExpr, () => {" \
"(value.binaryExpr === 'foo * on(test,blub) bar' ? it.skip : it)(value.binaryExpr, () => {"
'';
});
in
{
postPatch = builtins.replaceStrings [ "${old.passthru.assets}" ] [ "${assets}" ] (
builtins.unsafeDiscardStringContext old.postPatch
);
passthru = old.passthru // {
inherit assets;
};
}
);
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
(_pythonFinal: pythonPrev: {
backrefs = pythonPrev.backrefs.overridePythonAttrs (old: {
# regex measures its timeout in process CPU time, while this test used
# wall time and could miss the timeout when a busy builder descheduled it.
postPatch = (old.postPatch or "") + ''
substituteInPlace tests/test_bregex.py \
--replace-fail "time.time()" "time.process_time()"
'';
});
pytest-xdist = pythonPrev.pytest-xdist.overridePythonAttrs (old: {
# The suite exercises its own worker pools. Run the outer suite with one
# worker and allow inner workers more time on heavily loaded builders.
postPatch = (old.postPatch or "") + ''
substituteInPlace testing/test_remote.py \
--replace-fail "WAIT_TIMEOUT = 10.0" "WAIT_TIMEOUT = 60.0"
'';
preCheck = builtins.replaceStrings [ "--numprocesses=$NIX_BUILD_CORES" ] [ "--numprocesses=1" ] (
old.preCheck or ""
);
# This test deliberately crashes workers past the restart limit and
# races while checking which replacement message was emitted.
disabledTests = (old.disabledTests or [ ]) ++ [
"test_max_worker_restart_tests_queued"
];
});
jupyter-server = pythonPrev.jupyter-server.overridePythonAttrs (old: {
# The kernel reply arrived after the one-second outer deadline when the
# builder was heavily loaded. Keep the regression test but allow it the
# same margin as the other resource-sensitive tests.
postPatch = (old.postPatch or "") + ''
substituteInPlace tests/services/kernels/test_connection.py \
--replace-fail \
"await asyncio.wait_for(asyncio.wrap_future(conn2.request_kernel_info()), timeout=1.0)" \
"await asyncio.wait_for(asyncio.wrap_future(conn2.request_kernel_info()), timeout=10.0)"
'';
});
scipy = pythonPrev.scipy.overridePythonAttrs (old: {
# x86-64-v3 FFT implementations produce rounding differences outside
# these tests' strict tolerances. We accept the numerical-precision
# risk for our workloads.
disabledTests = (old.disabledTests or [ ]) ++ [
"test_roundtrip_float32"
"test_roundtrip_scaling"
];
});
sentry-sdk = pythonPrev.sentry-sdk.overridePythonAttrs (old: {
# This test globally mocks threading.current_thread while another
# thread is running. On Python 3.14, Thread.join can race with that
# mock and exhaust its single side effect before the worker removes it.
disabledTests = (old.disabledTests or [ ]) ++ [
"test_get_current_thread_meta_main_thread"
];
});
torchaudio = pythonPrev.torchaudio.overridePythonAttrs (old: {
# x86-64-v3 pitch shifting produces batch-versus-single-item numerical
# differences up to 2.9e-6. We accept that audio-precision risk for our
# workloads.
disabledTests = (old.disabledTests or [ ]) ++ [
"test_batch_pitch_shift"
];
});
torchcodec = pythonPrev.torchcodec.overridePythonAttrs (old: {
# For these 8 kHz MP3 cases, the x86-64-v3 API and CLI codec paths
# differ in 0.8% of decoded samples. Retain the original tolerance for
# 99% of samples and accept the localized audio-precision risk.
postPatch = (old.postPatch or "") + ''
substituteInPlace test/test_encoders.py \
--replace-fail \
'if sys.platform == "darwin":' \
'if sys.platform == "darwin" or (
format == "mp3"
and sample_rate == 8_000
and asset is SINE_MONO_S32
and bit_rate in (None, 0)
and num_channels in (None, 1)
):'
'';
});
})
];
}
+60
View File
@@ -0,0 +1,60 @@
# Compatibility fixes for packages rebuilt with x86-64-v3.
#
# The v3 baseline enables instructions that expose source assumptions hidden
# by the generic x86-64 build. Keep compile fixes here, separate from test
# exclusions, until upstream or nixpkgs incorporates them.
_final: prev:
let
patchAbseilBmi2Include =
package:
package.overrideAttrs (old: {
# GCC and Clang prohibit including their internal BMI2 header directly.
# The public umbrella provides the same intrinsics with the required
# compiler setup.
postPatch = (old.postPatch or "") + ''
substituteInPlace third_party/abseil-cpp/absl/container/internal/raw_hash_set.h \
--replace-fail "#include <bmi2intrin.h>" "#include <immintrin.h>"
'';
});
removeSiblingOutputChecks =
package:
package.overrideAttrs (old: {
# Nix 2.34 can validate a partial multi-output rebuild against only the
# outputs still being realised. PostgreSQL's checks then reject valid
# sibling names such as "out" and "lib". Keep the test suite and
# disallowed-requisite checks; accept the loss of cross-output checks.
outputChecks = builtins.mapAttrs (
_output: checks: builtins.removeAttrs checks [ "disallowedReferences" ]
) (old.outputChecks or { });
});
electron43Unwrapped = patchAbseilBmi2Include prev.electron_43.unwrapped;
electron43 = prev.electron_43.override {
electron-unwrapped = electron43Unwrapped;
};
signalCallPackage =
path: args:
let
package = prev.callPackage path args;
in
if builtins.baseNameOf path == "webrtc.nix" then patchAbseilBmi2Include package else package;
in
prev.lib.optionalAttrs ((prev.stdenv.hostPlatform.gcc.arch or null) == "x86-64-v3") {
deno =
let
librusty_v8 = patchAbseilBmi2Include prev.deno.passthru.librusty_v8;
in
prev.deno.override { inherit librusty_v8; };
electron_43 = electron43;
postgresql = removeSiblingOutputChecks prev.postgresql;
postgresql_18 = removeSiblingOutputChecks prev.postgresql_18;
signal-desktop = prev.signal-desktop.override {
electron_43 = electron43;
callPackage = signalCallPackage;
};
}
-43
View File
@@ -6,49 +6,6 @@ authors = [{ name = "Richie Cahill", email = "richie@tmmworkshop.com" }]
requires-python = "~=3.14.0"
readme = "README.md"
license = "MIT"
# these dependencies are a best effort and aren't guaranteed to work
# for up-to-date dependencies, see overlays/default.nix
dependencies = [
"alembic",
"apprise",
"beautifulsoup4",
"bm25s",
"ebooklib",
"fastapi",
"fastapi-cli",
"httpx",
"jinja2",
"pgvector",
"psycopg[binary]",
"pydantic",
"pydantic-settings",
"python-multipart",
"sqlalchemy[asyncio]",
"tenacity",
"tiktoken",
"tinytuya",
"typer",
"uvicorn",
"websockets",
"yake",
]
[project.scripts]
database = "python.database_cli:app"
whisper-transcribe = "python.tools.whisper.transcribe:main"
[dependency-groups]
dev = [
"aiosqlite",
"mypy",
"pyfakefs",
"pytest-asyncio",
"pytest-cov",
"pytest-mock",
"pytest-xdist",
"pytest",
"ruff",
]
[tool.ruff]
+1 -1
View File
@@ -14,7 +14,7 @@ DEFAULT_BASE_BRANCH = "main"
DEFAULT_BRANCH = "automation/update-flake-lock"
DEFAULT_GITEA_URL = "https://gitea.tmmworkshop.com"
PR_LABELS = ["dependencies", "automated", "flake_lock_update"]
PR_CHECK_WORKFLOWS = ["build_systems.yml", "treefmt.yml", "pytest.yml"]
PR_CHECK_WORKFLOWS = ["build_systems.yml", "treefmt.yml"]
PR_TITLE = "Update flake.lock"
PR_BODY = "Automated flake.lock update."
+18
View File
@@ -176,6 +176,21 @@ def create_zfs_datasets() -> None:
run_output(("zfs", "create", "root_pool/home"))
run_output(("zfs", "create", "-o", "reservation=1G", "root_pool/var"))
run_output(("zfs", "create", "-o", "compression=zstd-9", "-o", "reservation=10G", "root_pool/nix"))
run_output(
(
"zfs",
"create",
"-o",
"sync=disabled",
"-o",
"redundant_metadata=some",
"-o",
"normalization=none",
"-o",
"utf8only=off",
"root_pool/nix_build",
)
)
datasets = run_output(("zfs", "list", "-o", "name"))
expected_datasets = {
@@ -183,6 +198,7 @@ def create_zfs_datasets() -> None:
"root_pool/home",
"root_pool/var",
"root_pool/nix",
"root_pool/nix_build",
}
missing_datasets = expected_datasets.difference(datasets.splitlines())
if missing_datasets:
@@ -248,6 +264,7 @@ def create_nix_hardware_file(mnt_dir: str, disks: Sequence[str], encrypt: str |
' "/home" = {\n device = "root_pool/home";\n fsType = "zfs";\n };\n\n'
' "/var" = {\n device = "root_pool/var";\n fsType = "zfs";\n };\n\n'
' "/nix" = {\n device = "root_pool/nix";\n fsType = "zfs";\n };\n\n'
' "/nix/var/nix/builds" = {\n device = "root_pool/nix_build";\n fsType = "zfs";\n };\n\n'
' "/boot" = {\n'
f' device = "/dev/disk/by-uuid/{get_boot_drive_id(disks[0])}";\n'
' fsType = "vfat";\n options = [\n "fmask=0077"\n'
@@ -270,6 +287,7 @@ def install_nixos(mnt_dir: str, disks: Sequence[str], encrypt: str | None) -> No
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/home", f"{mnt_dir}/home"))
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/var", f"{mnt_dir}/var"))
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/nix", f"{mnt_dir}/nix"))
run_output(("mount", "-o", "X-mount.mkdir", "-t", "zfs", "root_pool/nix_build", f"{mnt_dir}/nix/var/nix/builds"))
for disk in disks:
run_output(("mkfs.vfat", "-n", "EFI", f"{disk}-part1"))
+25 -5
View File
@@ -5,10 +5,13 @@ from __future__ import annotations
import logging
from os import getenv
from apprise import Apprise
import httpx
logger = logging.getLogger(__name__)
SIGNAL_API_URL = "http://localhost:8989/v2/send"
SIGNAL_API_TIMEOUT = 4.0
def signal_alert(body: str, title: str = "") -> None:
"""Send a signal alert.
@@ -17,14 +20,31 @@ def signal_alert(body: str, title: str = "") -> None:
body (str): The body of the alert.
title (str, optional): The title of the alert. Defaults to "".
"""
apprise_client = Apprise()
from_phone = getenv("SIGNAL_ALERT_FROM_PHONE")
to_phone = getenv("SIGNAL_ALERT_TO_PHONE")
if not from_phone or not to_phone:
logger.info("SIGNAL_ALERT_FROM_PHONE or SIGNAL_ALERT_TO_PHONE not set")
return
apprise_client.add(f"signal://localhost:8989/{from_phone}/{to_phone}")
# Apprise's Signal integration did not support titles, so preserve that behavior.
if title:
logger.debug("Signal does not support notification titles; ignoring title")
apprise_client.notify(title=title, body=body)
try:
response = httpx.post(
SIGNAL_API_URL,
json={
"message": body,
"number": from_phone,
"recipients": [to_phone],
"text_mode": "normal",
},
timeout=SIGNAL_API_TIMEOUT,
follow_redirects=True,
)
except httpx.HTTPError:
logger.exception("Unable to contact the Signal API")
return
if response.status_code not in {httpx.codes.OK, httpx.codes.CREATED}:
logger.error("Signal API returned HTTP status %d", response.status_code)
-1
View File
@@ -1 +0,0 @@
"""system_tests."""
-99
View File
@@ -1,99 +0,0 @@
"""Validate Jeeves."""
from __future__ import annotations
import logging
from copy import copy
from re import search
from time import sleep
from typing import TYPE_CHECKING
from python.common import bash_wrapper
from python.zfs import Zpool
if TYPE_CHECKING:
from collections.abc import Sequence
logger = logging.getLogger(__name__)
def zpool_tests(pool_names: Sequence[str], zpool_capacity_threshold: int = 90) -> list[str] | None:
"""Check the zpool health and capacity.
Args:
pool_names (Sequence[str]): A list of pool names to test.
zpool_capacity_threshold (int, optional): The threshold for the zpool capacity. Defaults to 90.
Returns:
list[str] | None: A list of errors if any.
"""
logger.info("Testing zpool")
errors: list[str] = []
for pool_name in pool_names:
pool = Zpool(pool_name)
if pool.health != "ONLINE":
errors.append(f"{pool.name} is {pool.health}")
if pool.capacity >= zpool_capacity_threshold:
errors.append(f"{pool.name} is low on space")
upgrade_status, _ = bash_wrapper("zpool upgrade")
if not search(r"Every feature flags pool has all supported and requested features enabled.", upgrade_status):
errors.append("ZPool out of date run `sudo zpool upgrade -a`")
return errors
def systemd_tests(
service_names: Sequence[str],
max_retries: int = 30,
retry_delay_secs: int = 1,
retryable_statuses: Sequence[str] | None = None,
valid_statuses: Sequence[str] | None = None,
) -> list[str] | None:
"""Tests a systemd services.
Args:
service_names (Sequence[str]): A list of service names to test.
max_retries (int, optional): The maximum number of retries. Defaults to 30.
minimum value is 1.
retry_delay_secs (int, optional): The delay between retries in seconds. Defaults to 1.
minimum value is 1.
retryable_statuses (Sequence[str] | None, optional): A list of retryable statuses. Defaults to None.
valid_statuses (Sequence[str] | None, optional): A list of valid statuses. Defaults to None.
Returns:
list[str] | None: A list of errors if any.
"""
logger.info("Testing systemd service")
max_retries = max(max_retries, 1)
retry_delay_secs = max(retry_delay_secs, 1)
last_try = max_retries - 1
if retryable_statuses is None:
retryable_statuses = ("inactive\n", "activating\n")
if valid_statuses is None:
valid_statuses = ("active\n",)
service_names_set = set(service_names)
errors: set[str] = set()
for retry in range(max_retries):
if not service_names_set:
break
logger.info(f"Testing systemd service in {retry + 1} of {max_retries}")
service_names_to_test = copy(service_names_set)
for service_name in service_names_to_test:
service_status, _ = bash_wrapper(f"systemctl is-active {service_name}")
if service_status in valid_statuses:
service_names_set.remove(service_name)
continue
if service_status in retryable_statuses and retry < last_try:
continue
errors.add(f"{service_name} is {service_status.strip()}")
sleep(retry_delay_secs)
return list(errors)
-67
View File
@@ -1,67 +0,0 @@
"""Validate {server_name}."""
import logging
import sys
import tomllib
from os import environ
from pathlib import Path # noqa: TC003 This is required for the typer CLI
from socket import gethostname
import typer
from python.common import configure_logger
from python.signal_alert import signal_alert
from python.system_tests.components import systemd_tests, zpool_tests
logger = logging.getLogger(__name__)
def load_config_data(config_file: Path) -> dict[str, list[str]]:
"""Load a TOML configuration file.
Args:
config_file (Path): The path to the configuration file.
Returns:
dict: The configuration data.
"""
return tomllib.loads(config_file.read_text())
def main(config_file: Path) -> None:
"""Main."""
configure_logger(level=environ.get("LOG_LEVEL", "INFO"))
server_name = gethostname()
logger.info(f"Starting {server_name} validation")
config_data = load_config_data(config_file)
errors: list[str] = []
try:
if config_data.get("zpools") and (zpool_errors := zpool_tests(config_data["zpools"])):
errors.extend(zpool_errors)
if config_data.get("services") and (systemd_errors := systemd_tests(config_data["services"])):
errors.extend(systemd_errors)
except Exception as error:
logger.exception(f"{server_name} validation failed")
errors.append(f"{server_name} validation failed: {error}")
if errors:
logger.error(f"{server_name} validation failed: \n{'\n'.join(errors)}")
signal_alert(f"{server_name} validation failed {errors}")
sys.exit(1)
logger.info(f"{server_name} validation passed")
def cli() -> None:
"""CLI."""
typer.run(main)
if __name__ == "__main__":
cli()
+1 -2
View File
@@ -8,7 +8,7 @@
# loader path, which NixOS does not provide globally.
ebook-search = pkgs.mkShell {
nativeBuildInputs = with pkgs; [
my_python
python314
uv
];
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
@@ -23,7 +23,6 @@
nix
home-manager
git
my_python
ssh-to-age
gnupg
+1 -2
View File
@@ -3,7 +3,6 @@
imports = [
"${inputs.self}/users/math"
"${inputs.self}/users/richie"
"${inputs.self}/users/steve"
"${inputs.self}/common/global"
"${inputs.self}/common/optional/docker.nix"
"${inputs.self}/common/optional/monitoring-agent.nix"
@@ -14,7 +13,7 @@
"${inputs.self}/common/optional/systemd-boot.nix"
"${inputs.self}/common/optional/tailscale.nix"
"${inputs.self}/common/optional/update.nix"
"${inputs.self}/common/optional/yubikey.nix"
"${inputs.self}/common/optional/x86-64-v3.nix"
"${inputs.self}/common/optional/zfs"
./hardware.nix
./syncthing.nix
+5
View File
@@ -50,6 +50,11 @@
fsType = "zfs";
};
"/nix/var/nix/builds" = {
device = "root_pool/nix_build";
fsType = "zfs";
};
"/var" = {
device = "root_pool/var";
fsType = "zfs";
+6
View File
@@ -22,6 +22,12 @@ hourly = 0
daily = 0
monthly = 0
["root_pool/nix_build"]
15_min = 1
hourly = 0
daily = 0
monthly = 0
["root_pool/models"]
15_min = 4
hourly = 24
+1
View File
@@ -9,6 +9,7 @@
"${inputs.self}/common/optional/systemd-boot.nix"
"${inputs.self}/common/optional/tailscale.nix"
"${inputs.self}/common/optional/update.nix"
"${inputs.self}/common/optional/x86-64-v3.nix"
"${inputs.self}/common/optional/zfs"
./docker
./hardware.nix
+5
View File
@@ -53,6 +53,11 @@
fsType = "zfs";
};
"/nix/var/nix/builds" = {
device = "root_pool/nix_build";
fsType = "zfs";
};
"/boot" = {
device = "/dev/disk/by-uuid/12CE-A600";
fsType = "vfat";
+15 -1
View File
@@ -4,6 +4,20 @@
...
}:
{
nixpkgs.overlays = [
(final: _prev: {
heater_python = final.python314.withPackages (
ps: with ps; [
fastapi
pydantic
tinytuya
typer
uvicorn
]
);
})
];
networking.firewall.allowedTCPPorts = [ 8124 ];
systemd.services.heater-api = {
@@ -17,7 +31,7 @@
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.my_python}/bin/python -m python.heater.main --host 0.0.0.0 --port 8124";
ExecStart = "${pkgs.heater_python}/bin/python -m python.heater.main --host 0.0.0.0 --port 8124";
EnvironmentFile = "/etc/heater.env";
Restart = "on-failure";
RestartSec = "5s";
+4 -3
View File
@@ -68,7 +68,6 @@
paho-mqtt # for mqtt
psycopg2 # for postgresql
py-improv-ble-client # for esphome
pymodbus # for modbus
pyopenweathermap # for weather
pymetno # for met.no weather
uiprotect # for ubiquiti integration
@@ -76,10 +75,12 @@
jsonpath # for rest sensors
monarchmoneycommunity # for monarch
];
extraComponents = [ "isal" ];
extraComponents = [
"isal"
"modbus" # for victron modbus integration
];
customComponents = with pkgs.home-assistant-custom-components; [
garmin_connect
pirate-weather
];
};
+71
View File
@@ -0,0 +1,71 @@
{ pkgs, ... }:
let
vars = import ./vars.nix;
in
{
virtualisation.docker.daemon.settings."data-root" = "${vars.containers}/docker";
# nixos-container hardcodes its state directory to /var/lib/nixos-containers,
# so route it to the shared container dataset with a bind mount.
fileSystems."/var/lib/nixos-containers" = {
device = "${vars.containers}/nixos-containers";
fsType = "none";
options = [ "bind" ];
};
systemd.services = {
prepare-docker-storage = {
description = "Create Docker storage directory";
requiredBy = [ "docker.service" ];
before = [ "docker.service" ];
requires = [ "zfs-mount.service" ];
after = [ "zfs-mount.service" ];
path = [
pkgs.coreutils
pkgs.util-linux
];
unitConfig = {
DefaultDependencies = false;
RequiresMountsFor = [ "/nix" ];
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mountpoint -q ${vars.containers}
install -d -m 0710 ${vars.containers}/docker
'';
};
prepare-nixos-container-storage = {
description = "Create NixOS container storage directory";
requiredBy = [ "var-lib-nixos\\x2dcontainers.mount" ];
before = [ "var-lib-nixos\\x2dcontainers.mount" ];
requires = [ "zfs-mount.service" ];
after = [ "zfs-mount.service" ];
path = [
pkgs.coreutils
pkgs.util-linux
];
unitConfig = {
DefaultDependencies = false;
RequiresMountsFor = [ "/nix" ];
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mountpoint -q ${vars.containers}
install -d -m 0755 ${vars.containers}/nixos-containers
'';
};
};
}
+2 -10
View File
@@ -4,10 +4,8 @@ let
in
{
imports = [
"${inputs.self}/users/dov"
"${inputs.self}/users/math"
"${inputs.self}/users/richie"
"${inputs.self}/users/steve"
"${inputs.self}/common/global"
"${inputs.self}/common/optional/docker.nix"
"${inputs.self}/common/optional/monitoring-agent.nix"
@@ -15,10 +13,12 @@ in
"${inputs.self}/common/optional/syncthing_base.nix"
"${inputs.self}/common/optional/tailscale.nix"
"${inputs.self}/common/optional/update.nix"
"${inputs.self}/common/optional/x86-64-v3.nix"
"${inputs.self}/common/optional/zfs"
./monitoring
./docker
./services
./containers.nix
./hardware.nix
./networking
./programs.nix
@@ -35,14 +35,6 @@ in
path = ./snapshot_config.toml;
EnvironmentFile = "${vars.secrets}/services/snapshot_manager";
};
zerotierone = {
enable = true;
joinNetworks = [
"e4da7455b2ae64ca"
"a09acf02330d37b9"
];
};
};
users.groups = {
+5
View File
@@ -96,6 +96,11 @@ in
fsType = "zfs";
};
"/nix/var/nix/builds" = {
device = "root_pool/nix_build";
fsType = "zfs";
};
"/var" = {
device = "root_pool/var";
fsType = "zfs";
+130 -89
View File
@@ -1,8 +1,7 @@
{
config,
lib,
outputs,
utils,
pkgs,
...
}:
@@ -12,6 +11,132 @@ let
cfg = config.services.nix_builder;
runnerUsername = "gitea-runner";
runnerUserid = 601;
runnerLabels = [
"self-hosted:host"
"nixos:host"
];
containerConfig =
{
config,
pkgs,
lib,
...
}:
let
giteaAutomationPython = pkgs.python314.withPackages (
ps: with ps; [
httpx
pydantic
typer
]
);
runnerConfigFile = (pkgs.formats.yaml { }).generate "gitea-runner.yaml" { };
registerRunner = pkgs.writeShellApplication {
name = "register-gitea-runner";
runtimeInputs = [
pkgs.coreutils
pkgs.hostname
config.services.gitea-actions-runner.package
];
text = builtins.readFile ./register_gitea_runner.sh;
};
in
{
networking = {
hostName = "nix-builder";
useDHCP = lib.mkDefault true;
interfaces.eth0.useDHCP = true;
# Ensure containers don't inherit the host's stub resolver (127.0.0.53) which was causing issues
useHostResolvConf = false;
};
nix.settings = {
cores = 8;
max-jobs = 2;
system-features = lib.mkAfter [
"gccarch-x86-64-v2"
"gccarch-x86-64-v3"
];
trusted-substituters = [
"https://cache.nixos.org"
"https://cache.tmmworkshop.com"
"https://nix-community.cachix.org"
];
substituters = [
"https://cache.nixos.org/?priority=2&want-mass-query=true"
"https://cache.tmmworkshop.com/?priority=2&want-mass-query=true"
"https://nix-community.cachix.org/?priority=10&want-mass-query=true"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"cache.tmmworkshop.com:jHffkpgbmEdstQPoihJPYW9TQe6jnQbWR2LqkNGV3iA="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
experimental-features = [
"flakes"
"nix-command"
];
sandbox = true;
allowed-users = [ runnerUsername ];
trusted-users = [
"root"
runnerUsername
];
};
users = {
users.${runnerUsername} = {
isSystemUser = true;
group = runnerUsername;
uid = runnerUserid;
};
groups.${runnerUsername}.gid = runnerUserid;
};
services.gitea-actions-runner.instances.builder = {
enable = true;
name = "jeeves-nix-builder";
url = "http://192.168.99.14:6443/";
labels = runnerLabels;
tokenFile = "/run/secrets/gitea-runners/registration-token";
settings.runner.timeout = "12h";
hostPackages = with pkgs; [
bash
coreutils
curl
gawk
gitMinimal
giteaAutomationPython
gnused
nix
nixfmt
nixos-rebuild
nodejs
ruff
treefmt
wget
];
};
systemd.services."gitea-runner-builder" = {
serviceConfig = {
DynamicUser = mkForce false;
User = mkForce runnerUsername;
Group = mkForce runnerUsername;
ExecStartPre = mkForce [
"${getExe registerRunner} builder http://192.168.99.14:6443/ ${runnerConfigFile} ${escapeShellArgs runnerLabels}"
];
};
};
system.stateVersion = "24.05";
};
sharedContainerPath =
(import "${pkgs.path}/nixos/lib/eval-config.nix" {
modules = [
{
boot.isNspawnContainer = true;
nixpkgs.pkgs = pkgs;
}
containerConfig
];
system = null;
}).config.system.build.toplevel;
in
{
options.services.nix_builder = {
@@ -48,9 +173,11 @@ in
containers = mapAttrs (
name: containerCfg:
mkIf containerCfg.enable {
path = sharedContainerPath;
autoStart = true;
privateNetwork = true;
hostBridge = cfg.bridgeName;
extraFlags = [ "--hostname=${name}" ];
bindMounts = {
host-nix = {
mountPoint = "/host-nix/var/nix/daemon-socket";
@@ -68,93 +195,6 @@ in
isReadOnly = false;
};
};
config =
{
config,
pkgs,
lib,
...
}:
{
networking = {
useDHCP = lib.mkDefault true;
interfaces.eth0.useDHCP = true;
# Ensure containers don't inherit the host's stub resolver (127.0.0.53) which was causing issues
useHostResolvConf = false;
};
nix.settings = {
trusted-substituters = [
"https://cache.nixos.org"
"https://cache.tmmworkshop.com"
"https://nix-community.cachix.org"
];
substituters = [
"https://cache.nixos.org/?priority=2&want-mass-query=true"
"https://cache.tmmworkshop.com/?priority=2&want-mass-query=true"
"https://nix-community.cachix.org/?priority=10&want-mass-query=true"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"cache.tmmworkshop.com:jHffkpgbmEdstQPoihJPYW9TQe6jnQbWR2LqkNGV3iA="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
experimental-features = [
"flakes"
"nix-command"
];
sandbox = true;
allowed-users = [ "gitea-runner" ];
trusted-users = [
"root"
"gitea-runner"
];
};
nixpkgs = {
overlays = builtins.attrValues outputs.overlays;
config.allowUnfree = true;
};
users = {
users.${runnerUsername} = {
isSystemUser = true;
group = runnerUsername;
uid = runnerUserid;
};
groups.${runnerUsername}.gid = runnerUserid;
};
services.gitea-actions-runner.instances.${name} = {
enable = true;
name = "jeeves-${name}";
url = "http://192.168.99.14:6443/";
labels = [
"self-hosted:host"
"nixos:host"
];
tokenFile = "/run/secrets/gitea-runners/registration-token";
hostPackages = with pkgs; [
bash
coreutils
curl
gawk
gitMinimal
gnused
my_python
nix
nixfmt
nixos-rebuild
nodejs
treefmt
wget
];
};
systemd.services."gitea-runner-${utils.escapeSystemdPath name}" = {
serviceConfig = {
DynamicUser = mkForce false;
User = mkForce runnerUsername;
Group = mkForce runnerUsername;
};
};
system.stateVersion = "24.05";
};
}
) cfg.containers;
@@ -165,6 +205,7 @@ in
value = {
requires = [ "gitea.service" ];
after = [ "gitea.service" ];
serviceConfig.CPUQuota = "800%";
};
}) (builtins.attrNames (filterAttrs (_: c: c.enable) cfg.containers))
);
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
legacy_instance_dir="$STATE_DIRECTORY/$(hostname)"
instance_dir="$STATE_DIRECTORY/$1"
runner_url="$2"
runner_config_file="$3"
shift 3
runner_labels="$(IFS=,; printf '%s' "$*")"
if [ ! -e "$instance_dir" ] && [ -d "$legacy_instance_dir" ]; then
mv "$legacy_instance_dir" "$instance_dir"
fi
mkdir -vp "$instance_dir"
cd "$instance_dir" || exit 1
token_hash_file="$instance_dir/.token-hash"
token_hash_current="$(printf '%s' "$TOKEN" | sha256sum | cut -d' ' -f1)"
token_hash_stored="$(cat "$token_hash_file" 2>/dev/null || echo "")"
labels_file="$instance_dir/.labels"
labels_wanted="$(printf '%s\n' "$@" | sort)"
labels_current="$(cat "$labels_file" 2>/dev/null || echo 0)"
if [ ! -e "$instance_dir/.runner" ] || [ "$labels_wanted" != "$labels_current" ] || [ "$token_hash_current" != "$token_hash_stored" ]; then
rm -v "$instance_dir/.runner" || true
gitea-runner register --no-interactive \
--instance "$runner_url" \
--token "$TOKEN" \
--name "jeeves-$(hostname)" \
--labels "$runner_labels" \
--config "$runner_config_file"
printf '%s' "$token_hash_current" > "$token_hash_file"
printf '%s\n' "$labels_wanted" > "$labels_file"
fi
+1
View File
@@ -17,6 +17,7 @@ sudo zpool create scratch -o ashift=12 -O acltype=posixacl -O atime=off -O dnode
# media datasets
sudo zfs create media/temp -o sync=disabled -o redundant_metadata=none
sudo zfs create media/secure -o encryption=aes-256-gcm -o keyformat=hex -o keylocation=file:///root/zfs.key
sudo zfs create media/secure/containers -o mountpoint=/zfs/media/containers -o compression=lz4 -o sync=disabled -o redundant_metadata=some -o normalization=none -o utf8only=off
sudo zfs create media/secure/docker -o compression=zstd-9
sudo zfs create media/secure/github-runners -o compression=zstd-9 -o sync=disabled
sudo zfs create media/secure/notes -o copies=2
@@ -1,80 +0,0 @@
{
...
}:
let
vars = import ../vars.nix;
in
{
systemd.tmpfiles.rules = [
"d ${vars.docker_configs}/camofox-browser 0750 root root - -"
];
containers.camofox-browser = {
autoStart = true;
privateNetwork = false;
bindMounts = {
camofox-browser = {
hostPath = "${vars.docker_configs}/camofox-browser";
mountPoint = "/var/lib/camofox-browser";
isReadOnly = false;
};
};
config =
{
pkgs,
lib,
...
}:
{
networking.hostName = "camofox-browser";
environment.systemPackages = with pkgs; [
ffmpeg
git
nodejs
python3Packages.yt-dlp
];
systemd.services.camofox-browser = {
description = "Camofox browser server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = {
CAMOFOX_HOST = "127.0.0.1";
CAMOFOX_PORT = "9377";
HOME = "/var/lib/camofox-browser";
};
path = with pkgs; [
bash
coreutils
git
nodejs
];
serviceConfig = {
Restart = "always";
RestartSec = "5s";
WorkingDirectory = "/var/lib/camofox-browser";
};
script = ''
set -eu
app_dir=/var/lib/camofox-browser/app
if [ ! -d "$app_dir/.git" ]; then
git clone --depth 1 https://github.com/jo-inc/camofox-browser "$app_dir"
fi
cd "$app_dir"
if [ ! -d node_modules ]; then
npm install
fi
exec npm start
'';
};
system.stateVersion = lib.mkDefault "24.05";
};
};
}
+40 -1
View File
@@ -6,8 +6,47 @@
let
vars = import ../vars.nix;
stateDir = "${vars.services}/gems";
gemsPackages =
ps: with ps; [
fastapi
jinja2
pydantic
pydantic-settings
python-multipart
typer
uvicorn
];
in
{
nixpkgs.overlays = [
(final: _prev: {
gems_python = final.python314.withPackages gemsPackages;
gems_test_python = final.python314.withPackages (
ps:
gemsPackages ps
++ (with ps; [
httpx
pytest
pytest-asyncio
pytest-xdist
])
);
gems_tests =
final.runCommand "gems-tests"
{
nativeBuildInputs = [ final.gems_test_python ];
}
''
export HOME="$TMPDIR"
cd ${inputs.self}
pytest -o cache_dir="$TMPDIR/pytest-cache" tests/gems
touch "$out"
'';
})
];
system.checks = [ pkgs.gems_tests ];
users.groups.gems = { };
users.users.gems = {
isSystemUser = true;
@@ -36,7 +75,7 @@ in
Type = "simple";
User = "gems";
Group = "gems";
ExecStart = "${pkgs.my_python}/bin/python -m python.gems.main --host 0.0.0.0 --port 8002";
ExecStart = "${pkgs.gems_python}/bin/python -m python.gems.main --host 0.0.0.0 --port 8002";
Restart = "on-failure";
RestartSec = "5s";
StandardOutput = "journal";
+1
View File
@@ -19,6 +19,7 @@ in
actions = {
ENABLED = true;
DEFAULT_ACTIONS_URL = "github";
ENDLESS_TASK_TIMEOUT = "12h";
};
service.DISABLE_REGISTRATION = true;
server = {
-12
View File
@@ -1,12 +0,0 @@
{
services.open-webui = {
enable = true;
host = "0.0.0.0";
environment = {
ANONYMIZED_TELEMETRY = "False";
DO_NOT_TRACK = "True";
SCARF_NO_ANALYTICS = "True";
OLLAMA_API_BASE_URL = "http://127.0.0.1:11434";
};
};
}
-26
View File
@@ -1,11 +1,7 @@
{
pkgs,
inputs,
...
}:
let
vars = import ../vars.nix;
in
{
systemd = {
services = {
@@ -30,21 +26,6 @@ in
ExecStart = "${pkgs.bash}/bin/bash -c 'echo 1 > /sys/bus/pci/devices/0000:61:00.0/remove'";
};
};
startup_validation = {
requires = [ "network-online.target" ];
after = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
description = "validates startup";
path = [ pkgs.zfs ];
environment = {
PYTHONPATH = "${inputs.self}/";
};
serviceConfig = {
EnvironmentFile = "${vars.secrets}/services/server-validation";
Type = "oneshot";
ExecStart = "${pkgs.my_python}/bin/python -m python.system_tests.validate_system '${./validate_system.toml}'";
};
};
};
timers = {
plex_permission = {
@@ -55,13 +36,6 @@ in
Unit = "plex_permission.service";
};
};
startup_validation = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "10min";
Unit = "startup_validation.service";
};
};
};
};
}
@@ -1,6 +0,0 @@
zpool = ["root_pool", "storage", "media"]
services = [
"audiobookshelf",
"docker",
"jellyfin",
]
+12
View File
@@ -23,6 +23,12 @@ hourly = 0
daily = 0
monthly = 0
["root_pool/nix_build"]
15_min = 1
hourly = 0
daily = 0
monthly = 0
["root_pool/var"]
15_min = 8
hourly = 24
@@ -60,6 +66,12 @@ daily = 30
monthly = 12
# media
["media/secure/containers"]
15_min = 2
hourly = 0
daily = 0
monthly = 0
["media/temp"]
15_min = 2
hourly = 0
+1
View File
@@ -5,6 +5,7 @@ let
in
{
inherit zfs_media zfs_storage zfs_scratch;
containers = "${zfs_media}/containers";
database = "${zfs_media}/database";
docker = "${zfs_media}/docker";
docker_configs = "${zfs_media}/docker/configs";
+1 -2
View File
@@ -10,13 +10,12 @@
"${inputs.self}/users/richie"
"${inputs.self}/common/global"
"${inputs.self}/common/optional/tailscale.nix"
"${inputs.self}/common/optional/x86-64-v3.nix"
./disk-config.nix
./haproxy
./monitoring.nix
];
nixpkgs.hostPlatform = "x86_64-linux";
boot = {
# Avoid consuming the VM's limited memory for /tmp.
tmp.useTmpfs = false;
@@ -1,35 +0,0 @@
{
pkgs,
inputs,
...
}:
{
systemd.services.agent-logger = {
description = "Unified agent logger";
after = [ "local-fs.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
AGENT_LOG_DB = "/var/lib/agent-logger/agent_log.sqlite";
HOME = "/home/richie";
PYTHONPATH = "${inputs.self}";
};
serviceConfig = {
Type = "simple";
User = "richie";
WorkingDirectory = "/home/richie";
ExecStart = "${pkgs.my_python}/bin/python -m python.agent_logger.main";
StateDirectory = "agent-logger";
Restart = "on-failure";
RestartSec = "5s";
StandardOutput = "journal";
StandardError = "journal";
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = "read-only";
PrivateTmp = true;
ReadOnlyPaths = [ "${inputs.self}" ];
};
};
}
+1 -1
View File
@@ -9,10 +9,10 @@
"${inputs.self}/common/optional/syncthing_base.nix"
"${inputs.self}/common/optional/systemd-boot.nix"
"${inputs.self}/common/optional/tailscale.nix"
"${inputs.self}/common/optional/x86-64-v3.nix"
"${inputs.self}/common/optional/yubikey.nix"
"${inputs.self}/common/optional/zfs"
./hardware.nix
./open_webui.nix
./programs.nix
./qmk.nix
./syncthing.nix
+8
View File
@@ -34,14 +34,22 @@
device = "root_pool/root";
fsType = "zfs";
};
"/home" = {
device = "root_pool/home";
fsType = "zfs";
};
"/nix/var/nix/builds" = {
device = "root_pool/nix_build";
fsType = "zfs";
};
"/var" = {
device = "root_pool/var";
fsType = "zfs";
};
"/boot" = {
device = "/dev/disk/by-uuid/12CE-A600";
fsType = "vfat";
-13
View File
@@ -1,13 +0,0 @@
{
services.open-webui = {
enable = true;
host = "0.0.0.0";
environment = {
ANONYMIZED_TELEMETRY = "False";
DO_NOT_TRACK = "True";
SCARF_NO_ANALYTICS = "True";
OLLAMA_API_BASE_URL = "https://ollama.com";
WEBUI_AUTH = "False";
};
};
}
-104
View File
@@ -1,104 +0,0 @@
"""test_components."""
from pytest_mock import MockerFixture
from python.system_tests.components import systemd_tests, zpool_tests
from python.zfs import Zpool
temp = "Every feature flags pool has all supported and requested features enabled.\n"
SYSTEM_TESTS_COMPONENTS = "python.system_tests.components"
def test_zpool_tests(mocker: MockerFixture) -> None:
"""test_zpool_tests."""
mock_zpool = mocker.MagicMock(spec=Zpool)
mock_zpool.health = "ONLINE"
mock_zpool.capacity = 70
mock_zpool.name = "Main"
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.Zpool", return_value=mock_zpool)
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper", return_value=(temp, ""))
errors = zpool_tests(("Main",))
assert errors == []
def test_zpool_tests_out_of_date(mocker: MockerFixture) -> None:
"""test_zpool_tests_out_of_date."""
mock_zpool = mocker.MagicMock(spec=Zpool)
mock_zpool.health = "ONLINE"
mock_zpool.capacity = 70
mock_zpool.name = "Main"
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.Zpool", return_value=mock_zpool)
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper", return_value=("", ""))
errors = zpool_tests(("Main",))
assert errors == ["ZPool out of date run `sudo zpool upgrade -a`"]
def test_zpool_tests_out_of_space(mocker: MockerFixture) -> None:
"""test_zpool_tests_out_of_space."""
mock_zpool = mocker.MagicMock(spec=Zpool)
mock_zpool.health = "ONLINE"
mock_zpool.capacity = 100
mock_zpool.name = "Main"
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.Zpool", return_value=mock_zpool)
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper", return_value=(temp, ""))
errors = zpool_tests(("Main",))
assert errors == ["Main is low on space"]
def test_zpool_tests_offline(mocker: MockerFixture) -> None:
"""test_zpool_tests_offline."""
mock_zpool = mocker.MagicMock(spec=Zpool)
mock_zpool.health = "OFFLINE"
mock_zpool.capacity = 70
mock_zpool.name = "Main"
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.Zpool", return_value=mock_zpool)
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper", return_value=(temp, ""))
errors = zpool_tests(("Main",))
assert errors == ["Main is OFFLINE"]
def test_systemd_tests(mocker: MockerFixture) -> None:
"""test_systemd_tests."""
mocker.patch(
f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper",
side_effect=[
("inactive\n", ""),
("active\n", ""),
],
)
errors = systemd_tests(("docker",))
assert errors == []
"""test_systemd_tests."""
def test_systemd_tests_multiple_negative_retries(mocker: MockerFixture) -> None:
"""test_systemd_tests_fail."""
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper", return_value=("active\n", ""))
errors = systemd_tests(("docker",), max_retries=-1, retry_delay_secs=-1)
assert errors == []
def test_systemd_tests_multiple_pass(mocker: MockerFixture) -> None:
"""test_systemd_tests_fail."""
mocker.patch(
f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper",
side_effect=[
("inactive\n", ""),
("activating\n", ""),
("active\n", ""),
],
)
errors = systemd_tests(
("docker",),
retryable_statuses=("inactive\n", "activating\n"),
valid_statuses=("active\n",),
)
assert errors == []
def test_systemd_tests_fail(mocker: MockerFixture) -> None:
"""test_systemd_tests_fail."""
mocker.patch(f"{SYSTEM_TESTS_COMPONENTS}.bash_wrapper", return_value=("inactive\n", ""))
errors = systemd_tests(("docker",), max_retries=5)
assert errors == ["docker is inactive"]
-63
View File
@@ -1,63 +0,0 @@
"""test_server_validate_scripts."""
from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING
import pytest
from pytest_mock import MockerFixture
from python.system_tests.validate_system import main
if TYPE_CHECKING:
from pyfakefs.fake_filesystem import FakeFilesystem
from pytest_mock import MockerFixture
VALIDATE_SYSTEM = "python.system_tests.validate_system"
def test_validate_system(mocker: MockerFixture, fs: FakeFilesystem) -> None:
"""test_validate_system."""
fs.create_file(
"/mock_snapshot_config.toml",
contents='zpools = ["root_pool", "storage", "media"]\nservices = ["docker"]\n',
)
mocker.patch(f"{VALIDATE_SYSTEM}.systemd_tests", return_value=None)
mocker.patch(f"{VALIDATE_SYSTEM}.zpool_tests", return_value=None)
main(Path("/mock_snapshot_config.toml"))
def test_validate_system_errors(mocker: MockerFixture, fs: FakeFilesystem) -> None:
"""test_validate_system_errors."""
fs.create_file(
"/mock_snapshot_config.toml",
contents='zpools = ["root_pool", "storage", "media"]\nservices = ["docker"]\n',
)
mocker.patch(f"{VALIDATE_SYSTEM}.signal_alert")
mocker.patch(f"{VALIDATE_SYSTEM}.systemd_tests", return_value=["systemd_tests error"])
mocker.patch(f"{VALIDATE_SYSTEM}.zpool_tests", return_value=["zpool_tests error"])
with pytest.raises(SystemExit) as exception_info:
main(Path("/mock_snapshot_config.toml"))
assert exception_info.value.code == 1
def test_validate_system_execution(mocker: MockerFixture, fs: FakeFilesystem) -> None:
"""test_validate_system_execution."""
fs.create_file(
"/mock_snapshot_config.toml",
contents='zpools = ["root_pool", "storage", "media"]\nservices = ["docker"]\n',
)
mocker.patch(f"{VALIDATE_SYSTEM}.signal_alert")
mocker.patch(f"{VALIDATE_SYSTEM}.systemd_tests", return_value=None)
mocker.patch(f"{VALIDATE_SYSTEM}.zpool_tests", side_effect=RuntimeError("zpool_tests error"))
with pytest.raises(SystemExit) as exception_info:
main(Path("/mock_snapshot_config.toml"))
assert exception_info.value.code == 1
+45 -5
View File
@@ -5,7 +5,7 @@ from __future__ import annotations
from os import environ
from typing import TYPE_CHECKING
from apprise import Apprise
import httpx
from python.signal_alert import signal_alert
@@ -19,14 +19,23 @@ def test_signal_alert(mocker: MockerFixture) -> None:
environ["SIGNAL_ALERT_TO_PHONE"] = "0987654321"
mock_logger = mocker.patch("python.signal_alert.logger")
mock_apprise_client = mocker.MagicMock(spec=Apprise)
mocker.patch("python.signal_alert.Apprise", return_value=mock_apprise_client)
mock_response = mocker.MagicMock(spec=httpx.Response, status_code=httpx.codes.CREATED)
mock_post = mocker.patch("python.signal_alert.httpx.post", return_value=mock_response)
signal_alert("test")
mock_logger.info.assert_not_called()
mock_apprise_client.add.assert_called_once_with("signal://localhost:8989/1234567890/0987654321")
mock_apprise_client.notify.assert_called_once_with(title="", body="test")
mock_post.assert_called_once_with(
"http://localhost:8989/v2/send",
json={
"message": "test",
"number": "1234567890",
"recipients": ["0987654321"],
"text_mode": "normal",
},
timeout=4.0,
follow_redirects=True,
)
def test_signal_alert_no_phones(mocker: MockerFixture) -> None:
@@ -39,3 +48,34 @@ def test_signal_alert_no_phones(mocker: MockerFixture) -> None:
signal_alert("test")
mock_logger.info.assert_called_once_with("SIGNAL_ALERT_FROM_PHONE or SIGNAL_ALERT_TO_PHONE not set")
def test_signal_alert_http_error(mocker: MockerFixture) -> None:
"""HTTP errors are logged rather than propagated."""
environ["SIGNAL_ALERT_FROM_PHONE"] = "1234567890"
environ["SIGNAL_ALERT_TO_PHONE"] = "0987654321"
mock_logger = mocker.patch("python.signal_alert.logger")
request = httpx.Request("POST", "http://localhost:8989/v2/send")
mocker.patch(
"python.signal_alert.httpx.post",
side_effect=httpx.ConnectError("connection failed", request=request),
)
signal_alert("test")
mock_logger.exception.assert_called_once_with("Unable to contact the Signal API")
def test_signal_alert_unsuccessful_response(mocker: MockerFixture) -> None:
"""Unexpected response statuses are logged."""
environ["SIGNAL_ALERT_FROM_PHONE"] = "1234567890"
environ["SIGNAL_ALERT_TO_PHONE"] = "0987654321"
mock_logger = mocker.patch("python.signal_alert.logger")
mock_response = mocker.MagicMock(spec=httpx.Response, status_code=httpx.codes.BAD_GATEWAY)
mocker.patch("python.signal_alert.httpx.post", return_value=mock_response)
signal_alert("test")
mock_logger.error.assert_called_once_with("Signal API returned HTTP status %d", httpx.codes.BAD_GATEWAY)
-26
View File
@@ -1,26 +0,0 @@
{
pkgs,
...
}:
{
users = {
users.dov = {
isNormalUser = true;
shell = pkgs.zsh;
group = "dov";
openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCoSBmMfvp6aThkrfkLQ4TDwZJD0HCC0lsTIRNREIAWeduNkVFdkO3T1SMLmCKJ+zlL9xziNBEqB8NFl4TabAhptIGlKgTOc8C9eDaPQMQV8PB/4DxZhCt7O2qb4Vfcz82IHPtdwwaIsGpssgh81mQ4tPtP8BI0TluRBy+2v095s20j+PYRGrAXJtOWpVY9zaXxEJ8dXDhHDF2xzxvUcwu9NsoY8t+4/ZJ1mrTTG+eGp5gLAKnSVhAGgsmqCY577Nkso1jSzKer1XcCiaGIedpLuTzmUbOFFEVhhTSy+Ki1NLEcjGW2e6Vyg5Pm8VGN75MqyDZsi5igv9Grxq62EHQ4mFea9rns48B74O/bNQ1OoLVO9u/HwdLCgBTZzptrCmNwML6kBWrmCogoH3ueVbHwDCW5kTTMBCoVV+HaZ+qDWu7xZVx49MuCK29QGZj/IrN0N7h78KL0NYajdei87R0mcmWGP0YaJTdCQ4iKi9c77BUYQp+Qpqt+mnIX0cgjQOU= dkruger@kzin" # cspell:disable-line
];
extraGroups = [
"audio"
"video"
"users"
];
uid = 1004;
};
groups.dov.gid = 1004;
};
}
-9
View File
@@ -1,9 +0,0 @@
{
imports = [
./direnv.nix
./git.nix
./zsh.nix
];
programs.starship.enable = true;
}
-8
View File
@@ -1,8 +0,0 @@
{
programs.direnv = {
enable = true;
enableZshIntegration = true;
nix-direnv.enable = true;
};
}
-15
View File
@@ -1,15 +0,0 @@
{
programs.git = {
enable = true;
signing.format = null;
settings = {
user = {
email = "dov.kruger@gmail.com";
name = "Dov Kruger";
};
pull.rebase = true;
color.ui = true;
};
lfs.enable = true;
};
}
-27
View File
@@ -1,27 +0,0 @@
{
programs.zsh = {
enable = true;
syntaxHighlighting.enable = true;
history.size = 10000;
oh-my-zsh = {
enable = true;
plugins = [
"git"
"docker"
"docker-compose"
"colored-man-pages"
"rust"
"systemd"
"tmux"
"ufw"
"z"
];
};
shellAliases = {
"lrt" = "eza --icons -lsnew";
"ls" = "eza";
"ll" = "eza --long --group";
"la" = "eza --all";
};
};
}
-22
View File
@@ -1,22 +0,0 @@
{ config, ... }:
{
imports = [
./cli
./programs.nix
./ssh_config.nix
];
programs = {
home-manager.enable = true;
git.enable = true;
};
home = {
username = "dov";
homeDirectory = "/home/${config.home.username}";
stateVersion = "24.05";
sessionVariables = {
FLAKE = "$HOME/dotfiles";
};
};
}
-56
View File
@@ -1,56 +0,0 @@
{ pkgs, ... }:
{
home.packages = with pkgs; [
# cli
bat
btop
eza
fd
ffmpegthumbnailer
fzf
git
gnupg
imagemagick
jq
ncdu
ouch
p7zip
poppler
rar
ripgrep
starship
tmux
unzip
yazi
zoxide
# system info
hwloc
lynis
pciutils
smartmontools
usbutils
# networking
iperf3
nmap
wget
# python
ruff
uv
# nodejs
nodejs
# Rust packages
trunk
wasm-pack
cargo-watch
cargo-generate
cargo-audit
cargo-update
# nix
nix-init
nix-output-monitor
nix-prefetch
nix-tree
nixfmt
treefmt
];
}
-6
View File
@@ -1,6 +0,0 @@
{
programs.ssh = {
enable = true;
enableDefaultConfig = false;
};
}
-5
View File
@@ -1,5 +0,0 @@
{
imports = [
../home/global.nix
];
}
+1 -38
View File
@@ -3,54 +3,17 @@
home.packages = with pkgs; [
# cli
bat
btop
eza
fd
ffmpegthumbnailer
fzf
git
gnupg
imagemagick
jq
ncdu
ouch
fastfetch
p7zip
poppler
rar
ripgrep
starship
tmux
unzip
yazi
zoxide
# system info
hwloc
lynis
pciutils
smartmontools
usbutils
# networking
iperf3
nmap
wget
# python
ruff
uv
# nodejs
nodejs
# Rust packages
trunk
wasm-pack
cargo-watch
cargo-generate
cargo-audit
cargo-update
# nix
nix-init
nix-output-monitor
nix-prefetch
nix-tree
nixfmt
treefmt
];
}
+4 -5
View File
@@ -1,12 +1,11 @@
{ inputs, pkgs, ... }:
{ pkgs, ... }:
{
imports = [
"${inputs.self}/users/shared/comms.nix"
"${inputs.self}/users/shared/games.nix"
"${inputs.self}/users/shared/sweet.nix"
./firefox
./comms.nix
./games.nix
./kitty.nix
./llm_tools.nix
./sweet.nix
./t3_code
./vscode
];
-257
View File
@@ -1,257 +0,0 @@
{ config, inputs, ... }:
{
imports = [ ./search_engines.nix ];
programs.firefox = {
configPath = "${config.xdg.configHome}/mozilla/firefox";
enable = true;
profiles.richie = {
extensions.packages = with inputs.firefox-addons.packages.x86_64-linux; [
bitwarden
darkreader
dearrow
fastforwardteam
return-youtube-dislikes
sponsorblock
ublock-origin
];
search = {
force = true;
default = "kagi";
order = [
"kagi"
"ddg"
"google"
];
};
settings = {
# SECTION: FASTFOX
# GENERAL
"content.notify.interval" = 100000;
# GFX
"gfx.canvas.accelerated.cache-items" = 4096;
"gfx.canvas.accelerated.cache-size" = 512;
"gfx.content.skia-font-cache-size" = 20;
# DISK CACHE
"browser.cache.jsbc_compression_level" = 3;
# MEDIA CACHE
"media.memory_cache_max_size" = 65536;
"media.cache_readahead_limit" = 7200;
"media.cache_resume_threshold" = 3600;
# IMAGE CACHE
"image.mem.decode_bytes_at_a_time" = 32768;
# NETWORK
"network.buffer.cache.size" = 262144;
"network.buffer.cache.count" = 128;
"network.http.max-connections" = 1800;
"network.http.max-persistent-connections-per-server" = 10;
"network.http.max-urgent-start-excessive-connections-per-host" = 5;
"network.http.accept-encoding" = "gzip, deflate, br, zstd";
"network.http.pacing.requests.enabled" = false;
"network.dnsCacheExpiration" = 3600;
"network.dns.max_high_priority_threads" = 8;
"network.ssl_tokens_cache_capacity" = 10240;
# SPECULATIVE LOADING
"network.dns.disablePrefetch" = true;
"network.prefetch-next" = false;
"network.predictor.enabled" = false;
# EXPERIMENTAL
"layout.css.grid-template-masonry-value.enabled" = true;
"dom.enable_web_task_scheduling" = true;
"layout.css.has-selector.enabled" = true;
"dom.security.sanitizer.enabled" = true;
# SECTION: SECUREFOX
# TRACKING PROTECTION
"browser.contentblocking.category" = "strict";
"urlclassifier.trackingSkipURLs" = "*.reddit.com, *.twitter.com, *.twimg.com, *.tiktok.com";
"urlclassifier.features.socialtracking.skipURLs" = "*.instagram.com, *.twitter.com, *.twimg.com";
"network.cookie.sameSite.noneRequiresSecure" = true;
"browser.download.start_downloads_in_tmp_dir" = true;
"browser.helperApps.deleteTempFileOnExit" = true;
"browser.uitour.enabled" = false;
"privacy.globalprivacycontrol.enabled" = true;
# OCSP & CERTS / HPKP
"security.OCSP.enabled" = 0;
"security.remote_settings.crlite_filters.enabled" = true;
"security.pki.crlite_mode" = 2;
# SSL / TLS
"security.ssl.treat_unsafe_negotiation_as_broken" = true;
"browser.xul.error_pages.expert_bad_cert" = true;
"security.tls.enable_0rtt_data" = false;
# DISK AVOIDANCE
"browser.privatebrowsing.forceMediaMemoryCache" = true;
"browser.sessionstore.interval" = 60000;
# SHUTDOWN & SANITIZING
"privacy.history.custom" = true;
# SEARCH / URL BAR
"browser.search.separatePrivateDefault.ui.enabled" = true;
"browser.urlbar.update2.engineAliasRefresh" = true;
# PREF: restore search engine suggestions
"browser.search.suggest.enabled" = true;
"browser.urlbar.suggest.quicksuggest.sponsored" = false;
"browser.urlbar.suggest.quicksuggest.nonsponsored" = false;
"browser.formfill.enable" = false;
"security.insecure_connection_text.enabled" = true;
"security.insecure_connection_text.pbmode.enabled" = true;
"network.IDN_show_punycode" = true;
# HTTPS-FIRST POLICY
"dom.security.https_first" = true;
"dom.security.https_first_schemeless" = true;
# PASSWORDS
"signon.formlessCapture.enabled" = false;
"signon.rememberSignons" = false;
"signon.privateBrowsingCapture.enabled" = false;
"network.auth.subresource-http-auth-allow" = 1;
"editor.truncate_user_pastes" = false;
# MIXED CONTENT + CROSS-SITE
"security.mixed_content.block_display_content" = true;
"security.mixed_content.upgrade_display_content" = true;
"security.mixed_content.upgrade_display_content.image" = true;
"pdfjs.enableScripting" = false;
"extensions.postDownloadThirdPartyPrompt" = false;
# HEADERS / REFERERS
"network.http.referer.XOriginTrimmingPolicy" = 2;
# CONTAINERS
"privacy.userContext.ui.enabled" = true;
# WEBRTC
"media.peerconnection.ice.proxy_only_if_behind_proxy" = true;
"media.peerconnection.ice.default_address_only" = true;
# SAFE BROWSING
"browser.safebrowsing.downloads.remote.enabled" = false;
# MOZILLA
# PREF: allow websites to ask you to receive site notifications
"permissions.default.desktop-notification" = 0; # allow websites to ask
# PREF: allow websites to ask you for your location
"permissions.default.geo" = 0;
"geo.provider.network.url" =
"https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%";
"permissions.manager.defaultsUrl" = "";
"webchannel.allowObject.urlWhitelist" = "";
# TELEMETRY
"datareporting.policy.dataSubmissionEnabled" = false;
"datareporting.healthreport.uploadEnabled" = false;
"toolkit.telemetry.unified" = false;
"toolkit.telemetry.enabled" = false;
"toolkit.telemetry.server" = "data:,";
"toolkit.telemetry.archive.enabled" = false;
"toolkit.telemetry.newProfilePing.enabled" = false;
"toolkit.telemetry.shutdownPingSender.enabled" = false;
"toolkit.telemetry.updatePing.enabled" = false;
"toolkit.telemetry.bhrPing.enabled" = false;
"toolkit.telemetry.firstShutdownPing.enabled" = false;
"toolkit.telemetry.coverage.opt-out" = true;
"toolkit.coverage.opt-out" = true;
"toolkit.coverage.endpoint.base" = "";
"browser.ping-centre.telemetry" = false;
"browser.newtabpage.activity-stream.feeds.telemetry" = false;
"browser.newtabpage.activity-stream.telemetry" = false;
# EXPERIMENTS
"app.shield.optoutstudies.enabled" = false;
"app.normandy.enabled" = false;
"app.normandy.api_url" = "";
# CRASH REPORTS
"breakpad.reportURL" = "";
"browser.tabs.crashReporting.sendReport" = false;
"browser.crashReports.unsubmittedCheck.autoSubmit2" = false;
# DETECTION
"captivedetect.canonicalURL" = "";
"network.captive-portal-service.enabled" = false;
"network.connectivity-service.enabled" = false;
# SECTION: PESKYFOX
# MOZILLA UI
"browser.privatebrowsing.vpnpromourl" = "";
"extensions.getAddons.showPane" = false;
"extensions.htmlaboutaddons.recommendations.enabled" = false;
"browser.discovery.enabled" = false;
"browser.shell.checkDefaultBrowser" = false;
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons" = false;
"browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features" = false;
"browser.preferences.moreFromMozilla" = false;
"browser.tabs.tabmanager.enabled" = false;
"browser.aboutConfig.showWarning" = false;
"browser.aboutwelcome.enabled" = false;
# THEME ADJUSTMENTS
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
"browser.compactmode.show" = true;
"browser.display.focus_ring_on_anything" = true;
"browser.display.focus_ring_style" = 0;
"browser.display.focus_ring_width" = 0;
"layout.css.prefers-color-scheme.content-override" = 2;
# COOKIE BANNER HANDLING
"cookiebanners.service.mode" = 1;
"cookiebanners.service.mode.privateBrowsing" = 1;
# FULLSCREEN NOTICE
"full-screen-api.transition-duration.enter" = "0 0";
"full-screen-api.transition-duration.leave" = "0 0";
"full-screen-api.warning.delay" = -1;
"full-screen-api.warning.timeout" = 0;
# URL BAR
"browser.urlbar.suggest.calculator" = true;
"browser.urlbar.unitConversion.enabled" = true;
"browser.urlbar.trending.featureGate" = false;
# NEW TAB PAGE
"browser.newtabpage.activity-stream.feeds.topsites" = false;
"browser.newtabpage.activity-stream.feeds.section.topstories" = false;
# POCKET
"extensions.pocket.enabled" = false;
# DOWNLOADS
"browser.download.always_ask_before_handling_new_types" = true;
"browser.download.manager.addToRecentDocs" = false;
# PDF
"browser.download.open_pdf_attachments_inline" = true;
# TAB BEHAVIOR
"browser.bookmarks.openInTabClosesMenu" = false;
"browser.menu.showViewImageInfo" = true;
"findbar.highlightAll" = true;
"layout.word_select.eat_space_to_next_word" = false;
# SECTION: MY OVERRIDES
"browser.startup.homepage" = "https://google.com";
"identity.fxaccounts.enabled" = false;
# SECTION SMOOTHFOX
# OPTION: SHARPEN SCROLLING *
"apz.overscroll.enabled" = true; # DEFAULT NON-LINUX
"mousewheel.min_line_scroll_amount" = 10; # 10-40; adjust this number to your liking; default=5
"general.smoothScroll.mouseWheel.durationMinMS" = 80; # default=50
"general.smoothScroll.currentVelocityWeighting" = "0.15"; # default=.25
"general.smoothScroll.stopDecelerationWeighting" = "0.6"; # default=.4
};
};
};
}
-3
View File
@@ -1,3 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16 0 0 7.16 0 16C0 23.08 4.58 29.06 10.94 31.18C11.74 31.32 12.04 30.84 12.04 30.42C12.04 30.04 12.02 28.78 12.02 27.44C8 28.18 6.96 26.46 6.64 25.56C6.46 25.1 5.68 23.68 5 23.3C4.44 23 3.64 22.26 4.98 22.24C6.24 22.22 7.14 23.4 7.44 23.88C8.88 26.3 11.18 25.62 12.1 25.2C12.24 24.16 12.66 23.46 13.12 23.06C9.56 22.66 5.84 21.28 5.84 15.16C5.84 13.42 6.46 11.98 7.48 10.86C7.32 10.46 6.76 8.82 7.64 6.62C7.64 6.62 8.98 6.2 12.04 8.26C13.32 7.9 14.68 7.72 16.04 7.72C17.4 7.72 18.76 7.9 20.04 8.26C23.1 6.18 24.44 6.62 24.44 6.62C25.32 8.82 24.76 10.46 24.6 10.86C25.62 11.98 26.24 13.4 26.24 15.16C26.24 21.3 22.5 22.66 18.94 23.06C19.52 23.56 20.02 24.52 20.02 26.02C20.02 28.16 20 29.88 20 30.42C20 30.84 20.3 31.34 21.1 31.18C27.42 29.06 32 23.06 32 16C32 7.16 24.84 0 16 0V0Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 924 B

@@ -1,99 +0,0 @@
{ pkgs, ... }:
{
programs.firefox.profiles.richie.search.engines = {
"Nix Options" = {
urls = [
{
template = "https://search.nixos.org/options";
params = [
{
name = "type";
value = "packages";
}
{
name = "channel";
value = "unstable";
}
{
name = "query";
value = "{searchTerms}";
}
];
}
];
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@o" ];
};
"Nix Packages" = {
urls = [
{
template = "https://search.nixos.org/packages";
params = [
{
name = "type";
value = "packages";
}
{
name = "channel";
value = "unstable";
}
{
name = "query";
value = "{searchTerms}";
}
];
}
];
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@n" ];
};
"Nix Packages pr-tracker" = {
urls = [
{
template = "https://nixpk.gs/pr-tracker.html?";
params = [
{
name = "pr";
value = "{searchTerms}";
}
];
}
];
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@nprt" ];
};
"kagi" = {
urls = [
{
template = "https://kagi.com/search?";
params = [
{
name = "q";
value = "{searchTerms}";
}
];
}
];
icon = ./kagi.png;
};
github = {
urls = [
{
template = "https://github.com/search?";
params = [
{
name = "q";
value = "{searchTerms}";
}
{
name = "type";
value = "code";
}
];
}
];
icon = ./github.svg;
definedAliases = [ "@g" ];
};
};
}
-13
View File
@@ -3,21 +3,14 @@
home.packages = with pkgs; [
# cli
bat
fd
ffmpegthumbnailer
fzf
git
gnupg
imagemagick
jq
ncdu
fastfetch
ouch
p7zip
poppler
rar
unzip
yazi
zoxide
# Home Assistant
esphome
@@ -35,8 +28,6 @@
# python
ruff
uv
# nodejs
nodejs
# Rust packages
bacon
cargo
@@ -51,9 +42,6 @@
rustfmt
trunk
wasm-pack
# cpp
clang-tools
clang_20
# nix
nix-init
nix-output-monitor
@@ -61,6 +49,5 @@
nix-tree
nixfmt
treefmt
codebase-memory-mcp
];
}
-44
View File
@@ -1,44 +0,0 @@
{
pkgs,
config,
...
}:
let
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
in
{
users = {
users.steve = {
isNormalUser = true;
shell = pkgs.zsh;
group = "steve";
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJH03VzDbUhzfhvwD+OsYh6GobODYaI9jdNdzWQoqFsp matth@Jove" # cspell:disable-line
];
extraGroups = [
"audio"
"video"
"wheel"
"users"
]
++ ifTheyExist [
"dialout"
"docker"
"hass"
"libvirtd"
"networkmanager"
"plugdev"
"scanner"
"transmission"
"uaccess"
"wireshark"
];
uid = 1005;
};
groups.steve.gid = 1005;
};
home-manager.users.steve = import ./systems/${config.networking.hostName}.nix;
}
-9
View File
@@ -1,9 +0,0 @@
{
imports = [
./direnv.nix
./git.nix
./zsh.nix
];
programs.starship.enable = true;
}
-8
View File
@@ -1,8 +0,0 @@
{
programs.direnv = {
enable = true;
enableZshIntegration = true;
nix-direnv.enable = true;
};
}
-15
View File
@@ -1,15 +0,0 @@
{
programs.git = {
enable = true;
signing.format = null;
settings = {
user = {
email = "matthew.michal11@gmail.com";
name = "Matthew Michal";
};
pull.rebase = true;
color.ui = true;
};
lfs.enable = true;
};
}
-28
View File
@@ -1,28 +0,0 @@
{
programs.zsh = {
enable = true;
syntaxHighlighting.enable = true;
history.size = 10000;
oh-my-zsh = {
enable = true;
plugins = [
"git"
"docker"
"docker-compose"
"colored-man-pages"
"rust"
"systemd"
"tmux"
"ufw"
"z"
];
};
shellAliases = {
"lrt" = "eza --icons -lsnew";
"ls" = "eza";
"ll" = "eza --long --group";
"la" = "eza --all";
};
};
}
-22
View File
@@ -1,22 +0,0 @@
{ config, ... }:
{
imports = [
./cli
./programs.nix
./ssh_config.nix
];
programs = {
home-manager.enable = true;
git.enable = true;
};
home = {
username = "steve";
homeDirectory = "/home/${config.home.username}";
stateVersion = "24.05";
sessionVariables = {
FLAKE = "$HOME/dotfiles";
};
};
}
-56
View File
@@ -1,56 +0,0 @@
{ pkgs, ... }:
{
home.packages = with pkgs; [
# cli
bat
btop
eza
fd
ffmpegthumbnailer
fzf
git
gnupg
imagemagick
jq
ncdu
ouch
p7zip
poppler
rar
ripgrep
starship
tmux
unzip
yazi
zoxide
# system info
hwloc
lynis
pciutils
smartmontools
usbutils
# networking
iperf3
nmap
wget
# python
ruff
uv
# nodejs
nodejs
# Rust packages
trunk
wasm-pack
cargo-watch
cargo-generate
cargo-audit
cargo-update
# nix
nix-init
nix-output-monitor
nix-prefetch
nix-tree
nixfmt
treefmt
];
}
-6
View File
@@ -1,6 +0,0 @@
{
programs.ssh = {
enable = true;
enableDefaultConfig = false;
};
}
-5
View File
@@ -1,5 +0,0 @@
{
imports = [
../home/global.nix
];
}
-5
View File
@@ -1,5 +0,0 @@
{
imports = [
../home/global.nix
];
}