diff --git a/.clang-format b/.clang-format deleted file mode 100644 index f6b8fdf..0000000 --- a/.clang-format +++ /dev/null @@ -1,2 +0,0 @@ ---- -BasedOnStyle: LLVM diff --git a/.gdbinit b/.gdbinit deleted file mode 100644 index 0199ab7..0000000 --- a/.gdbinit +++ /dev/null @@ -1,8 +0,0 @@ -file /nix/store/ijxm784gr0sx5p4d92rlag0ippyd0mvm-am-kernel-riscv32-none-elf-2024-07-10/libexec/am-kernels/demo - -set substitute-path /build/am-kernels /home/xin/repo/ysyx-workbench/am-kernels -set substitute-path /build/abstract-machine /home/xin/repo/ysyx-workbench/abstract-machine -# set debug remote 1 -target remote /tmp/gdbstub-diffu.sock -break *halt + 24 - diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..88bb85c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +eval_secrets.nix diff=sops diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml deleted file mode 100644 index 80bedb4..0000000 --- a/.gitea/workflows/build.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Build nix packages -on: [push] - -jobs: - build-matrix: - runs-on: nix - strategy: - matrix: - package: [ "default" ] - steps: - - uses: https://github.com/cachix/cachix-action@v14 - with: - name: ysyx - authToken: '${{ secrets.CACHIX_SIGNING_KEY }}' - - - uses: actions/checkout@v4 - - - name: Build - run: | - nix build -L .#${{ matrix.package }} diff --git a/.gitignore b/.gitignore index 6ba7f7d..9f05b1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,138 +1,3 @@ -.cache/ -.vscode/ -.direnv/ -build/ -.pre-commit-config.yaml - -# Created by https://www.toptal.com/developers/gitignore/api/c++,c,cmake -# Edit at https://www.toptal.com/developers/gitignore?templates=c++,c,cmake - -### C ### -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -### C++ ### -# Prerequisites - -# Compiled Object files -*.slo - -# Precompiled Headers - -# Compiled Dynamic libraries - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai - -# Executables - -### CMake ### -CMakeLists.txt.user -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake -_deps - -### CMake Patch ### -# External projects -*-prefix/ - -# End of https://www.toptal.com/developers/gitignore/api/c++,c,cmake -# Created by https://www.toptal.com/developers/gitignore/api/c++ -# Edit at https://www.toptal.com/developers/gitignore?templates=c++ - -### C++ ### -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# End of https://www.toptal.com/developers/gitignore/api/c++ +.direnv +.vscode +result diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..a716cb1 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,61 @@ +keys: + - &xin age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + - &host-calcite age1ytwfqfeez3dqtazyjltn7mznccwx3ua8djhned7n8mxqhw4p6e5s97skfa + - &host-raspite age1nugzw24upk8pz5lyz2z89qk8se4gpcsg3ypcs58nykncr56sevrsm8qpvj + - &host-sgp-00 age13s6rwd3wjk2x5wkn69tdczhl3l5d7mfmlv90efsv4q67jne43qss9tcakx + - &host-tok-00 age1t5nw2jx4dw67jkf72uxcxt72j7lq3xyj35lvl09f8kala90h2g2s2a5yvj + - &host-la-00 age1fw2sqaa5s9c8ml6ncsexkj8ar4288387ju92ytjys4awf9aw6smqqz94dh + - &host-massicot age1jle2auermhswqtehww9gqada8car5aczrx43ztzqf9wtcld0sfmqzaecta + - &host-weilite age17r3fxfmt6hgwe984w4lds9u0cnkf5ttq8hnqt800ayfmx7t8t5gqjddyml +creation_rules: + - path_regex: machines/calcite/secrets.yaml + key_groups: + - age: + - *xin + - *host-calcite + - path_regex: machines/raspite/secrets.yaml + key_groups: + - age: + - *xin + - *host-raspite + - path_regex: machines/massicot/secrets.yaml + key_groups: + - age: + - *xin + - *host-massicot + - path_regex: machines/dolomite/secrets/sgp-00.yaml + key_groups: + - age: + - *xin + - *host-sgp-00 + - path_regex: machines/dolomite/secrets/tok-00.yaml + key_groups: + - age: + - *xin + - *host-tok-00 + - path_regex: machines/dolomite/secrets/la-00.yaml + key_groups: + - age: + - *xin + - *host-la-00 + - path-regex: machines/weilite/secrets.yaml + key_groups: + - age: + - *xin + - *host-weilite + - path_regex: machines/secrets.yaml + key_groups: + - age: + - *xin + - *host-calcite + - *host-raspite + - *host-sgp-00 + - *host-tok-00 + - *host-la-00 + - *host-massicot + - path_regex: home/xin/secrets.yaml + key_groups: + - age: + - *xin + - *host-raspite + - *host-calcite diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 6f4e3f8..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.26) - -project(difftest) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_C_STANDARD 17) - -include(GNUInstallDirs) - -find_package(spdlog REQUIRED) - -include_directories(include) -add_subdirectory(src) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md deleted file mode 100644 index ded87f0..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# diffu diff --git a/default.nix b/default.nix deleted file mode 100644 index 240238c..0000000 --- a/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ lib -, stdenv -, cmake -, mini-gdbstub -, cli11 -, spdlog -}: stdenv.mkDerivation { - pname = "diffu"; - version = "0.0.0"; - - src = ./.; - - nativeBuildInputs = [ - cmake - mini-gdbstub - cli11 - spdlog - ]; -} diff --git a/difftest.toml b/difftest.toml deleted file mode 100644 index 3fdac6d..0000000 --- a/difftest.toml +++ /dev/null @@ -1,17 +0,0 @@ -# ref = "/home/xin/repo/spike-diff/build/lib/libspike-diff.so" -# ref-prefix = "spike_" -ref= "/home/xin/repo/ysyx-workbench/nemu/build/riscv32-nemu-interpreter-so" -ref-prefix = "nemu_" -# dut = "/home/xin/repo/ysyx-workbench/nemu/build/riscv32-nemu-interpreter-so" -# dut-prefix = "nemu_" - -dut = "/home/xin/repo/ysyx-workbench/npc/build/csrc/Flow/libFlow.so" -dut-prefix = "npc_" - -# dut = "/home/xin/repo/ysyx-workbench/nemu/build/riscv32-nemu-interpreter-so" -# dut-prefix = "nemu_" -listen = "/tmp/gdbstub-diffu.sock" -# listen = "127.0.0.1:1234" -images-path = "/nix/store/z7mc0y608145cfwlb2g1gsii7bij7li1-am-kernel-riscv32-none-elf-2024-07-10/share/am-kernels" -memory = "bench.bin" -# g = true diff --git a/flake.lock b/flake.lock index fae0e3e..12edbd9 100644 --- a/flake.lock +++ b/flake.lock @@ -1,6 +1,100 @@ { "nodes": { + "catppuccin": { + "locked": { + "lastModified": 1724156255, + "narHash": "sha256-rpUCeS/QZwQdJmDrvCm0hRi8bFvQNQKAnIMK5ZDBfpM=", + "owner": "catppuccin", + "repo": "nix", + "rev": "8886a68edadb1d93c7101337f995ffce4b410ff2", + "type": "github" + }, + "original": { + "owner": "catppuccin", + "repo": "nix", + "type": "github" + } + }, + "colmena": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "stable": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711386353, + "narHash": "sha256-gWEpb8Hybnoqb4O4tmpohGZk6+aerAbJpywKcFIiMlg=", + "owner": "zhaofengli", + "repo": "colmena", + "rev": "cd65ef7a25cdc75052fbd04b120aeb066c3881db", + "type": "github" + }, + "original": { + "owner": "zhaofengli", + "repo": "colmena", + "type": "github" + } + }, + "devshell": { + "inputs": { + "nixpkgs": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1722113426, + "narHash": "sha256-Yo/3loq572A8Su6aY5GP56knpuKYRvM2a1meP9oJZCw=", + "owner": "numtide", + "repo": "devshell", + "rev": "67cce7359e4cd3c45296fb4aaf6a19e2a9c757ae", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "revCount": 57, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" + } + }, + "flake-compat_3": { "flake": false, "locked": { "lastModified": 1696426674, @@ -16,6 +110,46 @@ "type": "github" } }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1722555600, + "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8471fe90ad337a8074e957b69ca4d0089218391d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1722555600, + "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8471fe90ad337a8074e957b69ca4d0089218391d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -52,10 +186,45 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "my-nixvim", + "nixvim", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ], + "nixpkgs-stable": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723803910, + "narHash": "sha256-yezvUuFiEnCFbGuwj/bQcqg7RykIEqudOy/RBrId0pc=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "bfef0ada09e2c8ac55bbcd0831bd0c9d42e651ba", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "gitignore": { "inputs": { "nixpkgs": [ - "pre-commit-hooks", + "my-nixvim", + "nixvim", + "git-hooks", "nixpkgs" ] }, @@ -73,13 +242,159 @@ "type": "github" } }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723986931, + "narHash": "sha256-Fy+KEvDQ+Hc8lJAV3t6leXhZJ2ncU5/esxkgt3b8DEY=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "2598861031b78aadb4da7269df7ca9ddfc3e1671", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723986931, + "narHash": "sha256-Fy+KEvDQ+Hc8lJAV3t6leXhZJ2ncU5/esxkgt3b8DEY=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "2598861031b78aadb4da7269df7ca9ddfc3e1671", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "my-nixvim": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": [ + "nixpkgs" + ], + "nixvim": "nixvim" + }, + "locked": { + "lastModified": 1724158316, + "narHash": "sha256-cz2N0vPfe0jmjxqKWh7dgVecLqmPLHQrvxGJk0atDbg=", + "ref": "refs/heads/master", + "rev": "a5eb7fe89ee8ba654f339d8f75cecb39851743ec", + "revCount": 4, + "type": "git", + "url": "https://git.xinyang.life/xin/nixvim" + }, + "original": { + "type": "git", + "url": "https://git.xinyang.life/xin/nixvim" + } + }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723859949, + "narHash": "sha256-kiaGz4deGYKMjJPOji/JVvSP/eTefrIA3rAjOnOpXl4=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "076b9a905af8a52b866c8db068d6da475839d97b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "repo": "nix-darwin", + "type": "github" + } + }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723950649, + "narHash": "sha256-dHMkGjwwCGj0c2MKyCjRXVBXq2Sz3TWbbM23AS7/5Hc=", + "owner": "Mic92", + "repo": "nix-index-database", + "rev": "392828aafbed62a6ea6ccab13728df2e67481805", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "nix-index-database", + "type": "github" + } + }, + "nix-vscode-extensions": { + "inputs": { + "flake-compat": "flake-compat_3", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724117347, + "narHash": "sha256-/nfm6P0owPtCRjT8ktq/8OChtg2HpkrvNaDJGm9N1Lk=", + "owner": "nix-community", + "repo": "nix-vscode-extensions", + "rev": "2ef60116ef361d988317cbe52a09acfeda7d3416", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-vscode-extensions", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1724067415, + "narHash": "sha256-WJBAEFXAtA41RMpK8mvw0cQ62CJkNMBtzcEeNIJV7b0=", + "owner": "NixOS", + "repo": "nixos-hardware", + "rev": "b09c46430ffcf18d575acf5c339b38ac4e1db5d2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "master", + "repo": "nixos-hardware", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1711703276, - "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", + "lastModified": 1723991338, + "narHash": "sha256-Grh5PF0+gootJfOJFenTTxDTYPidA3V28dqJ/WV7iis=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", + "rev": "8a3354191c0d7144db9756a74755672387b702ba", "type": "github" }, "original": { @@ -89,72 +404,165 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1722555339, + "narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + } + }, "nixpkgs-stable": { "locked": { - "lastModified": 1710695816, - "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", - "owner": "NixOS", + "lastModified": 1723938990, + "narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=", + "owner": "nixos", "repo": "nixpkgs", - "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "nixos-23.11", + "owner": "nixos", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } }, - "nur-xin": { + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1721524707, + "narHash": "sha256-5NctRsoE54N86nWd0psae70YSLfrOek3Kv1e8KoXe/0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "556533a23879fc7e5f98dd2e0b31a6911a213171", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1724160083, + "narHash": "sha256-ROiCJNYSbjO45ajyTfRxp+aqvX+R1M3xwlWOLtfD0iw=", + "owner": "xinyangli", + "repo": "nixpkgs", + "rev": "885d5117645517b70eb3922acfbb83226fc77dbb", + "type": "github" + }, + "original": { + "owner": "xinyangli", + "ref": "deploy", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixvim": { "inputs": { + "devshell": "devshell", + "flake-compat": "flake-compat_2", + "flake-parts": "flake-parts_2", + "git-hooks": "git-hooks", + "home-manager": "home-manager_2", + "nix-darwin": "nix-darwin", + "nixpkgs": "nixpkgs", + "nuschtosSearch": "nuschtosSearch", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1724127528, + "narHash": "sha256-fKtsvNQeLhPuz1O53x6Xxkd/yYecpolNXRq7mfvnXQk=", + "owner": "nix-community", + "repo": "nixvim", + "rev": "cb413995e1e101c76d755b7f131ce60c7ea3985d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixvim", + "type": "github" + } + }, + "nur": { + "locked": { + "lastModified": 1724159175, + "narHash": "sha256-3z9wRL+h+gTVFtecCUGrRaW6nvPPAtBCIDE9KAmZj7c=", + "owner": "nix-community", + "repo": "NUR", + "rev": "0b86d5643d99e3982471f0d79e553871c6f35396", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "nuschtosSearch": { + "inputs": { + "flake-utils": "flake-utils_2", "nixpkgs": [ + "my-nixvim", + "nixvim", "nixpkgs" ] }, "locked": { - "lastModified": 1721891452, - "narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=", - "ref": "refs/heads/master", - "rev": "de8ad578fc4fe527772cec23a7f660bde14c8570", - "revCount": 152, - "type": "git", - "url": "https://git.xinyang.life/xin/nur.git" - }, - "original": { - "type": "git", - "url": "https://git.xinyang.life/xin/nur.git" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils_2", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1712055707, - "narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "e35aed5fda3cc79f88ed7f1795021e559582093a", + "lastModified": 1723969429, + "narHash": "sha256-BuewfNEXEf11MIkJY+uvWsdLu1dIvgJqntWChvNdALg=", + "owner": "NuschtOS", + "repo": "search", + "rev": "a05d1805f2a2bc47d230e5e92aecbf69f784f3d0", "type": "github" }, "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", + "owner": "NuschtOS", + "repo": "search", "type": "github" } }, "root": { "inputs": { + "catppuccin": "catppuccin", + "colmena": "colmena", "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "nur-xin": "nur-xin", - "pre-commit-hooks": "pre-commit-hooks" + "home-manager": "home-manager", + "my-nixvim": "my-nixvim", + "nix-index-database": "nix-index-database", + "nix-vscode-extensions": "nix-vscode-extensions", + "nixos-hardware": "nixos-hardware", + "nixpkgs": "nixpkgs_2", + "nixpkgs-stable": "nixpkgs-stable", + "nur": "nur", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, + "locked": { + "lastModified": 1723501126, + "narHash": "sha256-N9IcHgj/p1+2Pvk8P4Zc1bfrMwld5PcosVA0nL6IGdE=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "be0eec2d27563590194a9206f551a6f73d52fa34", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" } }, "systems": { @@ -186,6 +594,28 @@ "repo": "default", "type": "github" } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "my-nixvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723808491, + "narHash": "sha256-rhis3qNuGmJmYC/okT7Dkc4M8CeUuRCSvW6kC2f3hBc=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "1d07739554fdc4f8481068f1b11d6ab4c1a4167a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 1ef76ad..eeccc83 100644 --- a/flake.nix +++ b/flake.nix @@ -1,57 +1,232 @@ { inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - nur-xin = { - url = "git+https://git.xinyang.life/xin/nur.git"; + # Pin nixpkgs to a specific commit + nixpkgs.url = "github:xinyangli/nixpkgs/deploy"; + nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-24.05"; + + home-manager = { + url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; - pre-commit-hooks = { - url = "github:cachix/pre-commit-hooks.nix"; + + nix-vscode-extensions = { + url = "github:nix-community/nix-vscode-extensions"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; + + nur = { + url = "github:nix-community/NUR"; + }; + + nixos-hardware = { + url = "github:NixOS/nixos-hardware/master"; + }; + + sops-nix = { + url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + flake-utils = { + url = "github:numtide/flake-utils"; + }; + + colmena = { + url = "github:zhaofengli/colmena"; + inputs.stable.follows = "nixpkgs"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; + + nix-index-database = { + url = "github:Mic92/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + my-nixvim = { + url = "git+https://git.xinyang.life/xin/nixvim"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + catppuccin.url = "github:catppuccin/nix"; }; - outputs = { self, ... }@inputs: with inputs; - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { - inherit system; overlays = [ - (self: super: { - mini-gdbstub = nur-xin.legacyPackages.${system}.mini-gdbstub; - }) + + outputs = + { self + , home-manager + , nixpkgs + , nixos-hardware + , flake-utils + , nur + , catppuccin + , my-nixvim + , ... + }@inputs: + let + nixvimOverlay = (final: prev: { + nixvim = self.packages.${prev.stdenv.system}.nixvim; + }); + overlayModule = { ... }: { + nixpkgs.overlays = [ + nixvimOverlay + (import ./overlays/add-pkgs.nix) ]; - }; - in - { - checks = { - pre-commit-check = pre-commit-hooks.lib.${system}.run { - src = ./.; - hooks = { - trim-trailing-whitespace.enable = true; - clang-format = { - enable = true; - types_or = pkgs.lib.mkForce [ "c" "c++" ]; - }; - nil.enable = true; - nixpkgs-fmt.enable = true; + }; + deploymentModule = { + deployment.targetUser = "xin"; + }; + sharedColmenaModules = [ + self.nixosModules.default + deploymentModule + ]; + sharedHmModules = [ + inputs.sops-nix.homeManagerModules.sops + inputs.nix-index-database.hmModules.nix-index + catppuccin.homeManagerModules.catppuccin + self.homeManagerModules + ]; + mkHome = user: host: { ... }: { + imports = [ + home-manager.nixosModules.home-manager + { + home-manager = { + sharedModules = sharedHmModules; + useGlobalPkgs = true; + useUserPackages = true; + extraSpecialArgs = { inherit inputs; }; }; + home-manager.users.${user} = (import ./home).${user}.${host}; + } + ]; + }; + mkHomeConfiguration = user: host: { + name = user; + value = home-manager.lib.homeManagerConfiguration { + pkgs = import nixpkgs { system = "x86_64-linux"; }; + modules = [ + (import ./home).${user}.${host} + overlayModule + ] ++ sharedHmModules; + extraSpecialArgs = { + inherit inputs; }; }; - devShells.default = with pkgs; (mkShell.override { stdenv = ccacheStdenv; }) { - inherit (self.checks.${system}.pre-commit-check) shellHook; - buildInputs = self.checks.${system}.pre-commit-check.enabledPackages; - packages = [ - clang-tools - cmake - ninja - gdb - cli11 - spdlog - mini-gdbstub + }; + mkNixos = { system, modules, specialArgs ? { } }: nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = specialArgs // { inherit inputs system; }; + modules = [ + self.nixosModules.default + nur.nixosModules.nur + ] ++ modules; + }; + in + { + nixpkgs = nixpkgs; + nixosModules.default = { imports = [ ./modules/nixos overlayModule ]; }; + homeManagerModules = import ./modules/home-manager; + + homeConfigurations = builtins.listToAttrs [ (mkHomeConfiguration "xin" "calcite") ]; + + colmenaHive = inputs.colmena.lib.makeHive { + meta = { + nixpkgs = import nixpkgs { + system = "x86_64-linux"; + }; + specialArgs = { + inherit inputs; + }; + }; + + massicot = { ... }: { + deployment.targetHost = "49.13.13.122"; + deployment.buildOnTarget = true; + + imports = [ + { nixpkgs.system = "aarch64-linux"; } + machines/massicot + ] ++ sharedColmenaModules; + }; + + tok-00 = { ... }: { + imports = [ + machines/dolomite + ] ++ sharedColmenaModules; + nixpkgs.system = "x86_64-linux"; + networking.hostName = "tok-00"; + system.stateVersion = "23.11"; + deployment = { + targetHost = "video01.namely.icu"; + buildOnTarget = false; + tags = [ "proxy" ]; + }; + }; + + la-00 = { ... }: { + imports = [ + machines/dolomite + ] ++ sharedColmenaModules; + nixpkgs.system = "x86_64-linux"; + networking.hostName = "la-00"; + system.stateVersion = "21.05"; + deployment = { + targetHost = "la-00.video.namely.icu"; + buildOnTarget = false; + tags = [ "proxy" ]; + }; + }; + + raspite = { ... }: { + deployment = { + targetHost = "raspite.local"; + buildOnTarget = false; + }; + nixpkgs.system = "aarch64-linux"; + imports = [ + "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" + nixos-hardware.nixosModules.raspberry-pi-4 + machines/raspite/configuration.nix + ] ++ sharedColmenaModules; + }; + + weilite = { ... }: { + imports = [ + machines/weilite + ] ++ sharedColmenaModules; + deployment = { + targetHost = "weilite.coho-tet.ts.net"; + targetPort = 22; + buildOnTarget = false; + }; + nixpkgs.system = "x86_64-linux"; + }; + }; + + nixosConfigurations = { + calcite = mkNixos { + system = "x86_64-linux"; + modules = [ + nixos-hardware.nixosModules.asus-zephyrus-ga401 + machines/calcite/configuration.nix + (mkHome "xin" "calcite") ]; }; - packages.default = pkgs.callPackage ./default.nix { }; - } + } // self.colmenaHive.nodes; + + } // flake-utils.lib.eachDefaultSystem (system: + let pkgs = nixpkgs.legacyPackages.${system}; in + { + devShells = { + default = pkgs.mkShell { + packages = with pkgs; [ nix git colmena sops nix-output-monitor nil nvd ]; + }; + }; + + packages = { + nixvim = my-nixvim.packages.${system}.default; + }; + } ); } diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..0c683f6 --- /dev/null +++ b/home/default.nix @@ -0,0 +1,5 @@ +{ + xin = { + calcite = import ./xin/calcite.nix; + }; +} \ No newline at end of file diff --git a/home/xin/calcite.nix b/home/xin/calcite.nix new file mode 100644 index 0000000..130bd00 --- /dev/null +++ b/home/xin/calcite.nix @@ -0,0 +1,77 @@ +{ config, pkgs, ... }@inputs: +{ + imports = [ + ./common + ]; + + programs.nix-index-database.comma.enable = true; + + home.username = "xin"; + home.homeDirectory = "/home/xin"; + home.stateVersion = "23.05"; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + accounts.email.accounts.gmail = { + primary = true; + address = "lixinyang411@gmail.com"; + flavor = "gmail.com"; + realName = "Xinyang Li"; + }; + + accounts.email.accounts.whu = { + address = "lixinyang411@whu.edu.cn"; + }; + + accounts.email.accounts.foxmail = { + address = "lixinyang411@foxmail.com"; + }; + + home.packages = with pkgs; [ + thunderbird + remmina + ]; + + # Theme + catppuccin = { + enable = true; + flavor = "mocha"; + }; + xdg.enable = true; + + i18n.inputMethod = { + enabled = "fcitx5"; + fcitx5.addons = with pkgs; [ fcitx5-rime ]; + }; + + custom-hm = { + alacritty = { enable = true; }; + direnv = { enable = true; }; + fish = { enable = true; }; + git = { enable = true; signing.enable = true; }; + neovim = { enable = true; }; + vscode = { enable = true; languages = { cxx = true; python = true; scala = true; latex = true; }; llm = true; }; + zellij = { enable = true; }; + }; + + programs.atuin = { + enable = true; + flags = [ "--disable-up-arrow" ]; + }; + + programs.firefox.enable = true; + + programs.firefox.policies = { + DefaultDownloadDirectory = "/media/data/Downloads"; + }; + + programs.firefox.profiles.default = { + isDefault = true; + userChrome = builtins.readFile "${pkgs.fetchgit { + url = "https://gist.github.com/0ded98af9fe3da35f3688f81364d8c14.git"; + rev = "11bb4f428382052bcbbceb6cc3fef97f3c939481"; + hash = "sha256-J11indzEGdUA0HSW8eFe5AjesOxCL/G05KwkJk9GZSY="; + }}/userChrome.css"; + }; +} diff --git a/home/xin/common/default.nix b/home/xin/common/default.nix new file mode 100644 index 0000000..6957c4d --- /dev/null +++ b/home/xin/common/default.nix @@ -0,0 +1,25 @@ +{ inputs, pkgs, lib, ... }: { + imports = [ ]; + + home.packages = with pkgs; [ + dig + du-dust # du + rust + zoxide # autojumper + ripgrep + file + man-pages + unar + tree + wget + tmux + ffmpeg + tealdeer + rclone + wl-clipboard + + inetutils + ]; + + # Required for standalone home configuration + nix.package = lib.mkForce pkgs.nixVersions.latest; +} diff --git a/home/xin/gold/default.nix b/home/xin/gold/default.nix new file mode 100644 index 0000000..192e11c --- /dev/null +++ b/home/xin/gold/default.nix @@ -0,0 +1,15 @@ +{ pkgs, home-manager, ... }: + home-manager.lib.homeManagerConfiguration { + inherit pkgs; + modules = [ + ../common + { + home.username = "xin"; + home.homeDirectory = "/home/xin"; + home.stateVersion = "23.05"; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + } + ]; + } diff --git a/home/xin/raspite/default.nix b/home/xin/raspite/default.nix new file mode 100644 index 0000000..d09be89 --- /dev/null +++ b/home/xin/raspite/default.nix @@ -0,0 +1,28 @@ + +{ config, pkgs, ... }: +{ + imports = [ + ../common + ]; + + home.username = "xin"; + home.homeDirectory = "/home/xin"; + home.stateVersion = "23.05"; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + accounts.email.accounts.gmail = { + primary = true; + address = "lixinyang411@gmail.com"; + flavor = "gmail.com"; + }; + + accounts.email.accounts.whu = { + address = "lixinyang411@whu.edu.cn"; + }; + + accounts.email.accounts.foxmail = { + address = "lixinyang411@foxmail.com"; + }; +} diff --git a/include/api.hpp b/include/api.hpp deleted file mode 100644 index 114aee8..0000000 --- a/include/api.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _DIFFTEST_API_H_ -#define _DIFFTEST_API_H_ - -#include -#include -#include -#include - -extern "C" { -#include -} - -// Target dynamic library has to implement these functions -struct DiffTargetApi { - typedef void (*cont_t)(void *args, gdb_action_t *res); - cont_t cont; - - typedef void (*stepi_t)(void *args, gdb_action_t *res); - stepi_t stepi; - - typedef int (*read_reg_t)(void *args, int regno, size_t *value); - read_reg_t read_reg; - - typedef int (*write_reg_t)(void *args, int regno, size_t value); - write_reg_t write_reg; - - typedef int (*read_mem_t)(void *args, size_t addr, size_t len, void *val); - read_mem_t read_mem; - - typedef int (*write_mem_t)(void *args, size_t addr, size_t len, void *val); - write_mem_t write_mem; - - typedef bool (*set_bp_t)(void *args, size_t addr, bp_type_t type); - set_bp_t set_bp; - - typedef bool (*del_bp_t)(void *args, size_t addr, bp_type_t type); - del_bp_t del_bp; - - typedef void (*on_interrupt_t)(void *args); - on_interrupt_t on_interrupt; - - typedef void (*init_t)(void *args); - init_t init; -}; - -struct TargetMeta { - std::string name; - std::filesystem::path libpath; - void *dlhandle; -}; - -class Target { -public: - DiffTargetApi ops; - TargetMeta meta; - std::vector args; // used as a buffer to store target specific values - - bool *do_difftest; - arch_info_t *isa_arch_info; - size_t *dbg_state_size; - gdb_action_t last_res; - - Target(){}; - Target(const std::string &name, const std::string &prefix, - const std::filesystem::path &path); - ~Target(); - - bool is_on_breakpoint() const; - bool is_on_breakpoint(const gdb_action_t &res) const; -}; - -#endif diff --git a/include/config.hpp b/include/config.hpp deleted file mode 100644 index bf27c5e..0000000 --- a/include/config.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include -#include -#include - -struct Config { - std::filesystem::path images_path = "./"; - std::filesystem::path memory_file; - std::vector refs; - std::vector refs_prefix; - std::filesystem::path dut; - std::string dut_prefix = ""; - std::string gdbstub_addr = "/tmp/gdbstub-diffu.sock"; - bool use_debugger = false; - - int cli_parse(int argc, char **argv); -}; - -extern Config config; diff --git a/include/difftest.hpp b/include/difftest.hpp deleted file mode 100644 index 211a6ff..0000000 --- a/include/difftest.hpp +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef _DIFFTEST_DIFFTEST_H_ -#define _DIFFTEST_DIFFTEST_H_ -#include "api.hpp" -#include -#include -#include -extern "C" { -#include -} - -class Difftest { -private: - Target dut; - std::vector refs; - - // target used for read_reg, write_reg, read_mem, write_mem - Target *current_target = &dut; - bool halt_status = false; - inline void start_run() { - __atomic_store_n(&halt_status, false, __ATOMIC_RELAXED); - }; - inline bool is_halt() { - return __atomic_load_n(&halt_status, __ATOMIC_RELAXED); - }; - -public: - Difftest(Target &&dut, std::vector &&refs); - - void setup(const std::filesystem::path &memory_file); - - // Export API for gdbstub - gdb_action_t cont(); - gdb_action_t stepi(); - int read_reg(int regno, size_t *value); - int write_reg(int regno, size_t value); - int read_mem(size_t addr, size_t len, void *val); - int write_mem(size_t addr, size_t len, void *val); - bool set_bp(size_t addr, bp_type_t type); - bool del_bp(size_t addr, bp_type_t type); - - struct ExecRet { - bool at_breakpoint; - bool do_difftest; - bool check_failed; - }; - ExecRet exec(size_t n, gdb_action_t *ret); - - bool check_all(); - int sync_regs_to_ref(void); - std::string list_targets(void); - std::string switch_target(int index); - - inline void halt() { - __atomic_store_n(&halt_status, true, __ATOMIC_RELAXED); - }; - - arch_info_t get_arch() const { return *dut.isa_arch_info; } - - static bool check(Target &dut, Target &ref) { - size_t pcref, pcdut; - bool passed = true; - dut.ops.read_reg(dut.args.data(), 32, &pcdut); - ref.ops.read_reg(ref.args.data(), 32, &pcref); - for (int r = 0; r < dut.isa_arch_info->reg_num; r++) { - size_t regdut = 0, regref = 0; - dut.ops.read_reg(dut.args.data(), r, ®dut); - ref.ops.read_reg(ref.args.data(), r, ®ref); - if (regdut != regref) { - spdlog::error("Reg {} different: \n\tPC:\t(ref) {:x}\t(dut) {:x}\n\t" - "value:\t(ref) {:x}\t(dut) {:x}", - r, pcref, pcdut, regref, regdut); - passed = false; - } - } - return passed; - }; - - class Iterator { - private: - Difftest &difftest; - size_t index; - bool on_dut; - - public: - Iterator(Difftest &difftest, size_t index, bool on_dut) - : difftest(difftest), index(index), on_dut(on_dut) {} - - Iterator &operator++() { - if (on_dut) { - on_dut = false; - } else { - ++index; - } - return *this; - } - - bool operator!=(const Iterator &other) const { - return index != other.index || on_dut != other.on_dut; - } - - Target &operator*() { - if (on_dut) { - return difftest.dut; - } else { - return difftest.refs.at(index); - } - } - }; - - Iterator begin() { return Iterator(*this, 0, true); } - - Iterator end() { return Iterator(*this, refs.size(), false); } -}; - -#endif diff --git a/machines/calcite/configuration.nix b/machines/calcite/configuration.nix new file mode 100644 index 0000000..8817563 --- /dev/null +++ b/machines/calcite/configuration.nix @@ -0,0 +1,328 @@ +{ config, pkgs, lib, ... }: + +{ + imports = + [ + # Include the results of the hardware scan. + ./hardware-configuration.nix + ./network.nix + ../sops.nix + ]; + + commonSettings = { + auth.enable = true; + nix = { + enableMirrors = true; + signing.enable = true; + }; + }; + + # Bootloader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.efi.efiSysMountPoint = "/boot/efi"; + # boot.kernelPackages = pkgs.linuxPackages_latest; + boot.kernelModules = [ "nvidia" "nvidia_modeset" "nvidia_uvm" ]; + boot.supportedFilesystems = [ "ntfs" ]; + boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; + + security.tpm2 = { + enable = true; + # expose /run/current-system/sw/lib/libtpm2_pkcs11.so + pkcs11.enable = true; + # TODO: Need this until fapi-config is fixed in NixOS + pkcs11.package = pkgs.tpm2-pkcs11.override { fapiSupport = false; }; + # TPM2TOOLS_TCTI and TPM2_PKCS11_TCTI env variables + tctiEnvironment.enable = true; + }; + services.gnome.gnome-keyring.enable = lib.mkForce false; + security.pam.services.login.enableGnomeKeyring = lib.mkForce false; + services.ssh-tpm-agent.enable = true; + + programs.ssh.agentPKCS11Whitelist = "${config.security.tpm2.pkcs11.package}/lib/libtpm_pkcs11.so"; + + networking.hostName = "calcite"; + + programs.steam = { + enable = true; + gamescopeSession = { enable = true; }; + }; + + programs.oidc-agent.enable = true; + programs.oidc-agent.providers = [ + { + issuer = "https://home.xinyang.life:9201"; + pubclient = { + client_id = "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69"; + client_secret = "UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh"; + scope = "openid offline_access profile email"; + }; + } + ]; + + programs.vim.defaultEditor = true; + + # Keep this even if enabled in home manager + programs.fish.enable = true; + environment.shells = [ pkgs.fish ]; + users.defaultUserShell = pkgs.fish; + + # Setup wireguard + # Set your time zone. + time.timeZone = "Asia/Shanghai"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.utf8"; + + i18n.extraLocaleSettings = { + LC_ADDRESS = "zh_CN.utf8"; + LC_IDENTIFICATION = "zh_CN.utf8"; + LC_MEASUREMENT = "zh_CN.utf8"; + LC_MONETARY = "zh_CN.utf8"; + LC_NAME = "zh_CN.utf8"; + LC_NUMERIC = "zh_CN.utf8"; + LC_PAPER = "zh_CN.utf8"; + LC_TELEPHONE = "zh_CN.utf8"; + LC_TIME = "en_US.utf8"; + }; + + # Enable the X11 windowing system. + services.xserver.enable = true; + + # Enable the GNOME Desktop Environment. + services.xserver.displayManager.gdm.enable = true; + services.xserver.desktopManager.gnome.enable = true; + + + # Configure keymap in X11 + services.xserver = { + xkb.layout = "us"; + xkb.variant = ""; + }; + # Keyboard mapping on internal keyboard + services.keyd = { + enable = true; + keyboards = { + "internal" = { + ids = [ "0b05:1866" ]; + settings = { + main = { + capslock = "overload(control, esc)"; + leftcontrol = "capslock"; + }; + }; + }; + }; + }; + + # Enable CUPS to print documents. + services.printing.enable = true; + # services.printing.drivers = [ pkgs.hplip ]; + + hardware.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + wireplumber.enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # If you want to use JACK applications, uncomment this + jack.enable = true; + }; + + # Define a user account. Don't forget to set a password with ‘passwd’. + users.users.xin = { + isNormalUser = true; + description = "xin"; + extraGroups = [ "networkmanager" "wheel" "wireshark" "tss" ]; + }; + + services.kanidm = { + enableClient = true; + clientSettings = { + uri = "https://auth.xinyang.life"; + }; + }; + + # Enable automatic login for the user. + services.displayManager.autoLogin.enable = true; + services.displayManager.autoLogin.user = "xin"; + + # Smart services + services.smartd.enable = true; + + # Workaround for GNOME autologin: https://github.com/NixOS/nixpkgs/issues/103746#issuecomment-945091229 + systemd.services."getty@tty1".enable = false; + systemd.services."autovt@tty1".enable = false; + + # Allow unfree packages + nixpkgs.config.allowUnfree = true; + nixpkgs.config.permittedInsecurePackages = [ + "openssl-1.1.1w" + # FIXME: Waiting for https://github.com/NixOS/nixpkgs/pull/335753 + "jitsi-meet-1.0.8043" + ]; + # List packages installed in system profile. To search, run: + # $ nix search wget + environment.systemPackages = with pkgs; [ + oidc-agent + # Filesystem + owncloud-client + nfs-utils + + # tesseract5 # ocr + ocrmypdf # pdfocr + + # ==== Development ==== # + # Python + # reference: https://nixos.wiki/wiki/Python + ( + let + my-python-packages = python-packages: with python-packages; [ + pandas + requests + numpy + pyyaml + setuptools + ]; + python-with-my-packages = python3.withPackages my-python-packages; + in + python-with-my-packages + ) + + # ==== GUI Softwares ==== # + + # Gnome tweaks + gnomeExtensions.paperwm + gnomeExtensions.search-light + gnomeExtensions.appindicator + gnomeExtensions.pano + gnome-tweaks + gnome-themes-extra + gnome.gnome-remote-desktop + bibata-cursors + gthumb + oculante + + # Multimedia + vlc + obs-studio + spotify + # IM + element-desktop + tdesktop + qq + wechat-uos + feishu + + # Password manager + bitwarden + + # Browser + (chromium.override { + commandLineArgs = [ + "--ozone-platform-hint=auto" + "--enable-wayland-ime" + ]; + }) + brave + + # Writting + zotero + # onlyoffice-bin + wpsoffice + zed-editor + + config.nur.repos.linyinfeng.wemeet + + virt-manager + ]; + + system.stateVersion = "22.05"; + + nix.extraOptions = '' + !include "${config.sops.secrets.github_public_token.path}" + ''; + + sops.secrets = { + restic_repo_calcite_password = { + owner = "xin"; + sopsFile = ./secrets.yaml; + }; + restic_repo_calcite = { + owner = "xin"; + sopsFile = ./secrets.yaml; + }; + sing_box_url = { + owner = "root"; + sopsFile = ./secrets.yaml; + }; + "gitea/envfile" = { + owner = "root"; + sopsFile = ./secrets.yaml; + }; + }; + custom.restic.enable = true; + custom.restic.repositoryFile = config.sops.secrets.restic_repo_calcite.path; + custom.restic.passwordFile = config.sops.secrets.restic_repo_calcite_password.path; + + custom.forgejo-actions-runner.enable = true; + custom.forgejo-actions-runner.tokenFile = config.sops.secrets."gitea/envfile".path; + + custom.prometheus = { + enable = true; + exporters.blackbox.enable = true; + }; + + services.ollama = { + enable = true; + acceleration = "cuda"; + }; + + + # MTP support + services.gvfs.enable = true; + + # Fonts + fonts = { + packages = with pkgs; [ + (nerdfonts.override { fonts = [ "FiraCode" ]; }) + noto-fonts + noto-fonts-emoji + liberation_ttf + mplus-outline-fonts.githubRelease + dina-font + proggyfonts + ubuntu_font_family + # Chinese + wqy_microhei + wqy_zenhei + noto-fonts-cjk-sans + noto-fonts-cjk-serif + source-han-sans + source-han-serif + ]; + fontconfig = { + defaultFonts = { + serif = [ "Noto Serif CJK SC" "Ubuntu" ]; + sansSerif = [ "Noto Sans CJK SC" "Ubuntu" ]; + monospace = [ "FiraCode NerdFont Mono" "Noto Sans Mono CJK SC" "Ubuntu" ]; + }; + }; + enableDefaultPackages = true; + }; + # Virtualization + virtualisation = { + libvirtd.enable = true; + podman = { + enable = true; + }; + docker = { + enable = true; + autoPrune.enable = true; + }; + }; + + services.nixseparatedebuginfod.enable = true; +} diff --git a/machines/calcite/hardware-configuration.nix b/machines/calcite/hardware-configuration.nix new file mode 100644 index 0000000..8a08bcd --- /dev/null +++ b/machines/calcite/hardware-configuration.nix @@ -0,0 +1,61 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "ahci" "usbhid" ]; + boot.initrd.kernelModules = [ ]; + boot.initrd.luks.devices.cryptroot = { + device = "/dev/disk/by-uuid/5a51f623-6fbd-4843-9f83-c895067e8e7d"; + }; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { # device = "/dev/disk/by-label/NIXROOT"; + device = "/dev/mapper/cryptroot"; + fsType = "btrfs"; + }; + + fileSystems."/boot/efi" = + { device = "/dev/disk/by-label/EFIBOOT"; + fsType = "vfat"; + }; + + fileSystems."/media/data" = + { device = "/dev/nvme0n1p7"; + fsType = "ntfs-3g"; + options = [ "rw" "uid=1000" "nofail" "x-systemd.device-timeout=2" ]; + }; + + swapDevices = + [ { device = "/dev/disk/by-label/NIXSWAP"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.tailscale0.useDHCP = lib.mkDefault true; + # networking.interfaces.virbr0.useDHCP = lib.mkDefault true; + # networking.interfaces.wg0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + hardware.graphics = { + enable = true; + enable32Bit = true; + }; + + hardware.nvidia = { + powerManagement.enable = true; + dynamicBoost.enable = lib.mkForce false; + }; +} diff --git a/machines/calcite/network.nix b/machines/calcite/network.nix new file mode 100644 index 0000000..3ed94c5 --- /dev/null +++ b/machines/calcite/network.nix @@ -0,0 +1,57 @@ +{ config, pkgs, ...}: + +{ + imports = [ ]; + + # Enable networking + networking = { + networkmanager = { + enable = true; + dns = "systemd-resolved"; + }; + }; + + services.resolved = { + enable = true; + extraConfig = '' + Cache=no + ''; + }; + + # Enable Tailscale + services.tailscale.enable = true; + # services.tailscale.useRoutingFeatures = "both"; + + services.dae.enable = true; + services.dae.configFile = "/var/lib/dae/config.dae"; + + custom.sing-box = { + enable = false; + configFile = { + urlFile = config.sops.secrets.sing_box_url.path; + hash = "6ca5bc8a16f8c413227690aceeee2c12c02cab09473c216b849af1e854b98588"; + }; + overrideSettings.experimental.clash_api.external_ui = "${config.nur.repos.linyinfeng.yacd}"; + }; + + # Open ports in the firewall. + networking.firewall.enable = true; + networking.firewall.allowedTCPPorts = [ 3389 ]; + networking.firewall.allowedUDPPorts = [ 3389 41641 ]; + networking.firewall.trustedInterfaces = [ + "tailscale0" + ]; + # Use nftables to manager firewall + networking.nftables.enable = true; + + # Add gsconnect, open firewall + programs.kdeconnect = { + enable = true; + package = pkgs.gnomeExtensions.gsconnect; + }; + + programs.wireshark = { + enable = true; + package = pkgs.wireshark-qt; + }; +} diff --git a/machines/calcite/secrets.yaml b/machines/calcite/secrets.yaml new file mode 100644 index 0000000..d0e1b64 --- /dev/null +++ b/machines/calcite/secrets.yaml @@ -0,0 +1,34 @@ +restic_repo_calcite_password: ENC[AES256_GCM,data:9ALTQULAMyLY4FIxuVztf9r3,iv:fObBBeqpHAVYl8YUopz9fZd3YWB+0sc8l+sR12rmxb4=,tag:l3xDc2/cpQr38X/cd7qMXA==,type:str] +restic_repo_calcite: ENC[AES256_GCM,data:+m9cjMXrZoCPg/S+/wV4WFBmg6pbFpqJ7JOdwOX0Z37bgoQXh4wcVPKK3CLd7G/iQjpO8SXaqJ1/d8r4Ydk21Gp1WqkB8g==,iv:DweDUujXp6i5XwwxeFjUsLDOJQJlRIT6GKPPxABNWiY=,tag:hdBHIjAcDQ1Ky/8hIv3+Ow==,type:str] +sing_box_url: ENC[AES256_GCM,data:2z2bDKdn51o1eaqhgE0pTg4FWcO8wcLNlnBZ69Q3Jm5GCxkXxsxN7DgqQvRVeakOHvaenQotF+nc6tlhKPsyzdQeG0yl3YYhGb9o3DkmpUjC6lalMSoiw1rSMVyBg4KYCWxmhR9iRurun62+5INGZwwHVqAjgWJhy/9+pdIFtgKyd/t0JhSU,iv:gIGbvRd88vZu3cVW7e4emZmmNO8QcubLrxS1sCwi4Co=,tag:AzLLtcA9jAbeuo6eWU6ilw==,type:str] +gitea: + envfile: ENC[AES256_GCM,data:bO1aMYm0kPTBbyPD5cweVRzNjiDK2WlWDsxz52L3faFg5HSVmBoi5DZC17XBXYw=,iv:lo9XEcwY4FPD/rRbnuiUviioMIiiphS26UgPro56DIU=,tag:0eKfsS0pYw+FPW+Y5dgisg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQMDdkc2RUVlR5aEFtZ01l + d3EzaG9RNFd1QTVrNFIrZlJmOXNVWG1jRFJNCnFqL2VrUFljdGdGMW02RnJkNGxm + dmhUS0pMOURyWWkyVlp1UDQ5ZG11U2cKLS0tIDBiNnI0Qm5QN04zQ3NpTVMzNGpY + eFlOKzdGa0FRZ0R5Um12bUE2T0ZzbHMK62B0QniOnaUKLGrrRV934PqbCbUKtK3u + hN+53kRiitkL1gmaGqRbfu4FMns9VPKdoyfECcJ39HyScl9ZEj8mMw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1ytwfqfeez3dqtazyjltn7mznccwx3ua8djhned7n8mxqhw4p6e5s97skfa + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBycTBkMWlWMncybUFraS9R + ZWFjOGdDRlFLV2RlZHVFSEhMdExaekJWMFQwCk5hbFJhQ3cvbG9qdERnbFhLTnFs + NXQvcndjNHBMdk1XOTYydVlDMzk0Y0UKLS0tIGpLM20zTnREdllxRlc1SnJEVFBZ + WGlLdXVoZlp3bEFXZjlMdG1VOUZDNUkKQ2NNTE3OsNUr2pOI7qeNFSCVkUIVRS+g + FG5FbJJcFihXqr+Qo0nZkq+xq07vIia7mKoqyoIfkKwweiVzDKyrkQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-08-14T01:46:18Z" + mac: ENC[AES256_GCM,data:+RuyHG1wLykJX792bkHvRXEiW7vDYj7i2tbR0MnZZUuFcr3xQDIuCW0/XnzxeX643k4iq+h/YUer/v7tIbCh75UXTG7oxQpfJhI8zMfaxKcCZBntD+wDhEmpWhgonOR/RwOAPMPz7FntJVvt9BHnpSLVjZC7KqVPohob0DRJs2Q=,iv:p6Lov35M8SN9RIV9I3D+3cO+wi3Kd2pVe08xgWYi/tM=,tag:aOMQauv2FFEsdwaS7WOraQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.0 diff --git a/machines/dolomite/bandwagon.nix b/machines/dolomite/bandwagon.nix new file mode 100644 index 0000000..32d2b9f --- /dev/null +++ b/machines/dolomite/bandwagon.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, modulesPath, ... }: +let + cfg = config.isBandwagon; +in +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + + options = { + isBandwagon = lib.mkEnableOption "Bandwagon instance"; + }; + + config = lib.mkIf cfg { + boot.initrd.availableKernelModules = [ "ata_piix" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-label/NIXROOT"; + fsType = "xfs"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-label/NIXBOOT"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; + networking.useDHCP = false; + networking.interfaces.ens18.useDHCP = true; + networking.interfaces.ens19.useDHCP = true; + }; +} diff --git a/machines/dolomite/default.nix b/machines/dolomite/default.nix new file mode 100644 index 0000000..22fc0e8 --- /dev/null +++ b/machines/dolomite/default.nix @@ -0,0 +1,193 @@ +{ config, lib, ... }: +let + awsHosts = [ "tok-00"]; + bwgHosts = [ "la-00" ]; +in +{ + imports = [ + ../sops.nix + ./bandwagon.nix + ./lightsail.nix + ]; + + + config = { + isBandwagon = builtins.elem config.networking.hostName bwgHosts; + isLightsail = builtins.elem config.networking.hostName awsHosts; + sops = { + secrets = { + wg_private_key = { + owner = "root"; + sopsFile = ./secrets + "/${config.networking.hostName}.yaml"; + }; + wg_ipv6_local_addr = { + owner = "root"; + sopsFile = ./secrets + "/${config.networking.hostName}.yaml"; + }; + }; + }; + boot.kernel.sysctl = { + "net.core.default_qdisc" = "fq"; + "net.ipv4.tcp_congestion_control" = "bbr"; + }; + + networking.firewall.trustedInterfaces = [ "tun0" ]; + + security.acme = { + acceptTerms = true; + certs.${config.deployment.targetHost} = { + email = "me@namely.icu"; + listenHTTP = ":80"; + }; + }; + networking.firewall.allowedTCPPorts = [ 80 8080 ]; + networking.firewall.allowedUDPPorts = [ ] ++ (lib.range 6311 6314); + + custom.prometheus = { + enable = true; + exporters.blackbox.enable = true; + }; + + custom.kanidm-client = { + enable = true; + uri = "https://auth.xinyang.life/"; + asSSHAuth = { + enable = true; + allowedGroups = [ "linux_users" ]; + }; + sudoers = [ "xin@auth.xinyang.life" ]; + }; + + services.openssh = { + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = lib.mkForce "no"; + GSSAPIAuthentication = "no"; + KerberosAuthentication = "no"; + }; + }; + services.fail2ban.enable = true; + programs.mosh.enable = true; + + security.sudo = { + execWheelOnly = true; + wheelNeedsPassword = false; + }; + + services.sing-box = let + singTls = { + enabled = true; + server_name = config.deployment.targetHost; + key_path = config.security.acme.certs.${config.deployment.targetHost}.directory + "/key.pem"; + certificate_path = config.security.acme.certs.${config.deployment.targetHost}.directory + "/cert.pem"; + }; + password = { + _secret = config.sops.secrets.singbox_password.path; + }; + uuid = { + _secret = config.sops.secrets.singbox_uuid.path; + }; + in + { + enable = true; + settings = { + dns = { + servers = [ + { + tag = "warp"; + address = "1.1.1.1"; + detour = "wg-out"; + } + { + tag = "directdns"; + address = "h3://8.8.8.8/dns-query"; + } + ]; + rules = [ + { + outbound = "wg-out"; + server = "warp"; + } + { + outbound = "direct"; + server = "directdns"; + } + ]; + }; + inbounds = [ + { + tag = "sg0"; + type = "trojan"; + listen = "::"; + listen_port = 8080; + users = [ + { name = "proxy"; + password = password; + } + ]; + tls = singTls; + } + ] ++ lib.forEach (lib.range 6311 6314) (port: { + tag = "sg" + toString (port - 6310); + type = "tuic"; + listen = "::"; + listen_port = port; + congestion_control = "bbr"; + users = [ + { name = "proxy"; + uuid = uuid; + password = password; + } + ]; + tls = singTls; + }); + outbounds = [ + { + type = "wireguard"; + tag = "wg-out"; + private_key = { + _secret = config.sops.secrets.wg_private_key.path; + }; + local_address = [ + "172.16.0.2/32" + { _secret = config.sops.secrets.wg_ipv6_local_addr.path; } + ]; + peers = [ + { public_key= "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="; + allowed_ips = [ "0.0.0.0/0" "::/0" ]; + server = "162.159.192.1"; + server_port = 500; + } + ]; + } + { + type = "direct"; + tag = "direct"; + } + { + type = "dns"; + tag = "dns-out"; + } + ]; + route = { + rules = [ + { + outbound = "dns-out"; + protocol = "dns"; + } + { + inbound = "sg0"; + outbound = "direct"; + } + { + inbound = "sg4"; + outbound = "direct"; + } + ]; + }; + }; + }; + }; + +} diff --git a/machines/dolomite/ec2-metadata-fetcher.sh b/machines/dolomite/ec2-metadata-fetcher.sh new file mode 100644 index 0000000..716aff7 --- /dev/null +++ b/machines/dolomite/ec2-metadata-fetcher.sh @@ -0,0 +1,66 @@ +metaDir=/etc/ec2-metadata +mkdir -m 0755 -p "$metaDir" +rm -f "$metaDir/*" + +get_imds_token() { + # retry-delay of 1 selected to give the system a second to get going, + # but not add a lot to the bootup time + curl \ + --silent \ + --show-error \ + --retry 3 \ + --retry-delay 1 \ + --fail \ + -X PUT \ + --connect-timeout 1 \ + -H "X-aws-ec2-metadata-token-ttl-seconds: 600" \ + http://169.254.169.254/latest/api/token +} + +preflight_imds_token() { + # retry-delay of 1 selected to give the system a second to get going, + # but not add a lot to the bootup time + curl \ + --silent \ + --show-error \ + --retry 3 \ + --retry-delay 1 \ + --fail \ + --connect-timeout 1 \ + -H "X-aws-ec2-metadata-token: $IMDS_TOKEN" \ + -o /dev/null \ + http://169.254.169.254/1.0/meta-data/instance-id +} + +try=1 +while [ $try -le 3 ]; do + echo "(attempt $try/3) getting an EC2 instance metadata service v2 token..." + IMDS_TOKEN=$(get_imds_token) && break + try=$((try + 1)) + sleep 1 +done + +if [ "x$IMDS_TOKEN" == "x" ]; then + echo "failed to fetch an IMDS2v token." +fi + +try=1 +while [ $try -le 10 ]; do + echo "(attempt $try/10) validating the EC2 instance metadata service v2 token..." + preflight_imds_token && break + try=$((try + 1)) + sleep 1 +done + +echo "getting EC2 instance metadata..." + +get_imds() { + # --fail to avoid populating missing files with 404 HTML response body + # || true to allow the script to continue even when encountering a 404 + curl --silent --show-error --fail --header "X-aws-ec2-metadata-token: $IMDS_TOKEN" "$@" || true +} + +get_imds -o "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path +(umask 077 && get_imds -o "$metaDir/user-data" http://169.254.169.254/1.0/user-data) +get_imds -o "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname +get_imds -o "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key diff --git a/machines/dolomite/lightsail.nix b/machines/dolomite/lightsail.nix new file mode 100644 index 0000000..bd8634c --- /dev/null +++ b/machines/dolomite/lightsail.nix @@ -0,0 +1,102 @@ +{ config, lib, pkgs, modulesPath, ... }: +with lib; +let + cfg = config.ec2; +in +{ + imports = [ + "${modulesPath}/profiles/headless.nix" + # Note: While we do use the headless profile, we also explicitly + # turn on the serial console on ttyS0 below. This is because + # AWS does support accessing the serial console: + # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configure-access-to-serial-console.html + "${modulesPath}/virtualisation/ec2-data.nix" + "${modulesPath}/virtualisation/amazon-init.nix" + ]; + + options = { + isLightsail = mkEnableOption "Lightsail instance"; + }; + + config = mkIf config.isLightsail { + boot.loader.grub.device = "/dev/nvme0n1"; + + # from nixpkgs amazon-image.nix + assertions = [ ]; + + boot.growPartition = true; + + fileSystems."/" = { + device = "/dev/disk/by-label/nixos"; + fsType = "ext4"; + autoResize = true; + }; + + fileSystems."/boot" = { + # The ZFS image uses a partition labeled ESP whether or not we're + # booting with EFI. + device = "/dev/disk/by-label/ESP"; + fsType = "vfat"; + }; + + boot.extraModulePackages = [ + config.boot.kernelPackages.ena + ]; + boot.initrd.kernelModules = [ "xen-blkfront" ]; + boot.initrd.availableKernelModules = [ "nvme" ]; + boot.kernelParams = [ "console=ttyS0,115200n8" "random.trust_cpu=on" ]; + + # Prevent the nouveau kernel module from being loaded, as it + # interferes with the nvidia/nvidia-uvm modules needed for CUDA. + # Also blacklist xen_fbfront to prevent a 30 second delay during + # boot. + boot.blacklistedKernelModules = [ "nouveau" "xen_fbfront" ]; + + boot.loader.grub.efiSupport = cfg.efi; + boot.loader.grub.efiInstallAsRemovable = cfg.efi; + boot.loader.timeout = 1; + boot.loader.grub.extraConfig = '' + serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 + terminal_output console serial + terminal_input console serial + ''; + + systemd.services.fetch-ec2-metadata = { + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = ["network-online.target"]; + path = [ pkgs.curl ]; + script = builtins.readFile ./ec2-metadata-fetcher.sh; + serviceConfig.Type = "oneshot"; + serviceConfig.StandardOutput = "journal+console"; + }; + + # Amazon-issued AMIs include the SSM Agent by default, so we do the same. + # https://docs.aws.amazon.com/systems-manager/latest/userguide/ami-preinstalled-agent.html + services.amazon-ssm-agent.enable = true; + + # Allow root logins only using the SSH key that the user specified + # at instance creation time. + services.openssh.enable = true; + services.openssh.settings.PermitRootLogin = "prohibit-password"; + + # Enable the serial console on ttyS0 + systemd.services."serial-getty@ttyS0".enable = true; + + # Creates symlinks for block device names. + services.udev.packages = [ pkgs.amazon-ec2-utils ]; + + # Force getting the hostname from EC2. + # networking.hostName = mkDefault ""; + + # Always include cryptsetup so that Charon can use it. + environment.systemPackages = [ pkgs.cryptsetup ]; + + # EC2 has its own NTP server provided by the hypervisor + networking.timeServers = [ "169.254.169.123" ]; + + # udisks has become too bloated to have in a headless system + # (e.g. it depends on GTK). + services.udisks2.enable = false; + }; +} diff --git a/machines/dolomite/secrets/la-00.yaml b/machines/dolomite/secrets/la-00.yaml new file mode 100644 index 0000000..266dae5 --- /dev/null +++ b/machines/dolomite/secrets/la-00.yaml @@ -0,0 +1,31 @@ +wg_private_key: ENC[AES256_GCM,data:jz/03kP/dj625Jweu0MEw9aGm3Z3M1f43cZqGy2eElCIDhD78n+zZAqOM8c=,iv:fZxuvZLx97YyDoafQXbqVYjqRYzZq90PJiri9vdjwro=,tag:0A9sGnSl3y3gpEuvsdRtGg==,type:str] +wg_ipv6_local_addr: ENC[AES256_GCM,data:W/uR+9kAKdXViAbZ0vEhC2eNwlzqX0x+LpzLrLCmQuVgRbZAtJCqfeE=,iv:pMZumU7fMV5MYX59hO7SEMLlG4m8DdPXeAiNgLxNzZk=,tag:xdGBpOBdWlc8Q9BDMv04sA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4WjRVY3BKdVU1WERrVzla + L1NNYWp2SFZEaW84b0h1clFGRHVmRDhnM3o0CkUrZjZKNHp2TGtrTXpyOHNVckJw + VURjOEVaR3VQU1pJY2NaOFBQRjVIdWcKLS0tIFBQRWRnNnk4aWxsQVhhdUdVWWpy + aG9Oa3lOY0JjY2tFU3ZTazcyZW5SM0kKRfTrM65aI5LMOHoGsls3PWChrY5pEz91 + EERpRd552+PxYBKvumI59mtdlD263d5kmlTxIIZXTOJ2fcl1bii2bg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1fw2sqaa5s9c8ml6ncsexkj8ar4288387ju92ytjys4awf9aw6smqqz94dh + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTdzk4ajV5ekNpZXNGTHdD + aVBLZDlSbzE1aG5LT0cvVVVlVDBNOWtackNVCjVnZDhYZmFoT21DZHNYT2pMVDF6 + ZW5UY1ZFRFdtbDdPZHZIWUVuWjhJMk0KLS0tIGR4UUYwcjJtZUFYYlJSS2d6Q3hZ + WVJYSWhOaTEvNUdYTXV6OThPenJaY0UKv3WK6gacUxO6PFklkW+jDMG5FgIUuEvN + RvvI9ZXRD4QwKW1mpVrxbC+fRqlKawyyyyikvHFGJvpts4/88IcgUQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-04-15T11:37:57Z" + mac: ENC[AES256_GCM,data:iCgvJMijsUjdBT9hMQx4owYkbp2nV1jORB5HGtz5IPHgI9A5FXAAPFtaSGgQSI3twSkYMU94NULjumCyyWt3syH5KK9itHgHwONyVFieyXLiWozqpN2Z0SA5G4SnK3E6X273br9gwNAj33I2MdS/3K8b4EOO2yEzilWmrW7f3rk=,iv:UD7uHrtq4O6+EsWFrjegTXHtQUFcnhKsu4J0e0srDtk=,tag:b0eJEeUJPwi4+rDPeBY7oA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/machines/dolomite/secrets/sgp-00.yaml b/machines/dolomite/secrets/sgp-00.yaml new file mode 100644 index 0000000..aef9c5d --- /dev/null +++ b/machines/dolomite/secrets/sgp-00.yaml @@ -0,0 +1,31 @@ +wg_private_key: ENC[AES256_GCM,data:UjxZ3iC5hxVcVJdEUJ3+myaQ/6MvghDw6eKa2flSuxMwFS31WB7r3evjlI0=,iv:BjgXCps6gx1ISghEO42x5aKb+c/n0P1V8FMVlPxAyLY=,tag:IkxCkpyVre+sFoBlRSFpMA==,type:str] +wg_ipv6_local_addr: ENC[AES256_GCM,data:ejDYuZjZCKcsvyUUKdXtxgBqWloIwYHmpc/YwCYq7O2thsxvOou6iSHf,iv:HDrMlec4svxHpZXMyRDzpdSKeJbTmkZPd98SHv2ZLhQ=,tag:LjpapuaJ6sl4USZC8xEU5w==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtUkpVa0dCSE1rTjZpaWR1 + cjJjc25iOEV4TnhQUWE4SjI4QWVZYXdVcHdBCkIrNlVrV2xJRURVSG9sUHozeE5s + NitsV1MvcENZTHhmU01CSTRVNENXUFEKLS0tIGgxakQ2cGIzdzg5QzRoT3ZSaXUx + TkN5MkNTNitWMzVKZWdhNGRIZ3VNNDgKQ6lwM6EowuGOrskUpwD8VGirravE+e3/ + Hkv5jLvvfVjmg0kvKlNRotTHrRUGV04JsbW7T9FfbKyYpmEb6oCrsg== + -----END AGE ENCRYPTED FILE----- + - recipient: age13s6rwd3wjk2x5wkn69tdczhl3l5d7mfmlv90efsv4q67jne43qss9tcakx + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjSUlkQzhYSGwyNnYvNHpQ + UktKOUZiYk56S0piVy9ZMFdYVFdsN1FEVkhVCnZETEM5MW84TlNpbm1hSXJtR2Yy + OEdrSi9lcmJOR2F1cUZqc0NyQjl4RDgKLS0tIHVLcnRicmVNd2MwVjB4cGFXTlBu + VkJCcXdqTkUzejNzSjIvV2YrVUc5Sm8KutTATsWJ5+yB/CFoGwTNshyI5LzwH4x5 + i5EIIkVPdxSIHrXUp0j6+RPWMJvEOFIE3dVwxz+MxqqHqtmEny1WKA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-12-19T12:31:51Z" + mac: ENC[AES256_GCM,data:AY0/qJ1ZXv4mQlHnG3uY2zQ0FhIYjHBWKyXXpv2/Q6yZkuSu6nIQk039nd+nk7lczXy2cylTHyjYv5vDF6BJARhu4jeYov6yMqYR8ye8rXjZKcOfrN5yv7LV6jyuzBRBkCWTQsaoR8ycKHlrMe+vkAGu50epdAQjAG+Qv6RkBiM=,iv:dMi2CququdEIg+g8NMUb8ioKwEkUqTP+nrivtsUYUUY=,tag:drHI6oJUUwN3JadCHbWWkg==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/machines/dolomite/secrets/tok-00.yaml b/machines/dolomite/secrets/tok-00.yaml new file mode 100644 index 0000000..5872491 --- /dev/null +++ b/machines/dolomite/secrets/tok-00.yaml @@ -0,0 +1,31 @@ +wg_private_key: ENC[AES256_GCM,data:jz/03kP/dj625Jweu0MEw9aGm3Z3M1f43cZqGy2eElCIDhD78n+zZAqOM8c=,iv:fZxuvZLx97YyDoafQXbqVYjqRYzZq90PJiri9vdjwro=,tag:0A9sGnSl3y3gpEuvsdRtGg==,type:str] +wg_ipv6_local_addr: ENC[AES256_GCM,data:W/uR+9kAKdXViAbZ0vEhC2eNwlzqX0x+LpzLrLCmQuVgRbZAtJCqfeE=,iv:pMZumU7fMV5MYX59hO7SEMLlG4m8DdPXeAiNgLxNzZk=,tag:xdGBpOBdWlc8Q9BDMv04sA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkYTc2a2J3ZXRXTlRxQTAx + UjZVTTVPa0FjbS9jekI5eXhLOTdUQTlBS2pJCnVPL2Q1d05QR2NpTDVZeDFpSCs3 + Yjh3aXkvdTBIOThVMGMzcUZmUWhtTjgKLS0tIFZvcy9zRVBRcDN0ekp0MEV5cEph + ZURTL3hnSHgwQTlSNklCK25icEM0SGsKq2jM6jXLfK38BgV0calwKLuHIcGw0zed + lT19Mt9jFsqmIkpJh1U9Ddpz63WND+7ruMdTZt6RWStIxww4m7pevg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1t5nw2jx4dw67jkf72uxcxt72j7lq3xyj35lvl09f8kala90h2g2s2a5yvj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiSXBqdXcxUDNkS29Gd3ZY + dTA3bmNUVThtTFJtdnFpSjZQT01TTXhpYUc4CkFhcm14eUw1YXIyWEViMSsyc3pr + VUJqWWdHMCtoRGQ1T3dMQlg3ZTZ5dGMKLS0tIGQvbGpFZTdrVUFURE9tdENCZGwr + aDBKbitCTmhxNXVNRGh6TVBvbkNhTUEKIuj7B4RdueX7BfExgzVoo6YJf59GsUHa + j5kIJ5UeTqWEBGBaXcPjhHMEQjYqwSBsVz2XJmsxLhi8WxejLio8FA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-12-19T12:30:24Z" + mac: ENC[AES256_GCM,data:f+7+O2ZVSZJhr0fJlfO/AtZC2N/7gsNu1f4cnUoXYFb1wobyU6tLkbwGqeyIulokgIDAU5lJ62TJXAjybe+kE+PGtpr61KS7dyiO0LjzcT/X898oBYvJ9jtkuxDzKM4ve570U7ZmS7Jbxt2NJEkcBvSUJRdJHH5l0sDrvmW8cwY=,iv:mno6jVUDUWxsO353hbCqGub+NYfk0XFsWzmWCBUt6Gg=,tag:KOw7HTy+pETha5pzx5Pf8Q==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/machines/massicot/default.nix b/machines/massicot/default.nix new file mode 100644 index 0000000..bcdc5f7 --- /dev/null +++ b/machines/massicot/default.nix @@ -0,0 +1,94 @@ +{ inputs, config, libs, pkgs, ... }: + +{ + imports = [ + inputs.sops-nix.nixosModules.sops + ./hardware-configuration.nix + ./networking.nix + ./services.nix + ]; + + sops = { + defaultSopsFile = ./secrets.yaml; + age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + secrets = { + storage_box_mount = { + owner = "root"; + }; + gts_env = { + owner = "gotosocial"; + }; + hedgedoc_env = { + owner = "hedgedoc"; + }; + grafana_cloud_api = { + owner = "prometheus"; + sopsFile = ../secrets.yaml; + }; + grafana_oauth_secret = { + owner = "grafana"; + }; + "miniflux/oauth2_secret" = { + owner = "root"; + }; + "forgejo/env" = { + owner = "forgejo"; + }; + }; + }; + + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.efi.efiSysMountPoint = "/boot"; + boot.loader.grub = { + enable = true; + efiSupport = true; + configurationLimit = 5; + }; + + fileSystems."/mnt/storage" = { + device = "//u380335-sub1.your-storagebox.de/u380335-sub1"; + fsType = "cifs"; + options = [ "credentials=${config.sops.secrets.storage_box_mount.path}" ]; + }; + + environment.systemPackages = with pkgs; [ + cifs-utils + git + ]; + + system.stateVersion = "22.11"; + + networking = { + hostName = "massicot"; + }; + + custom.kanidm-client = { + enable = true; + uri = "https://auth.xinyang.life/"; + asSSHAuth = { + enable = true; + allowedGroups = [ "linux_users" ]; + }; + sudoers = [ "xin@auth.xinyang.life" ]; + }; + + security.sudo = { + execWheelOnly = true; + wheelNeedsPassword = false; + }; + + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "no"; + GSSAPIAuthentication = "no"; + KerberosAuthentication = "no"; + }; + }; + services.fail2ban.enable = true; + programs.mosh.enable = true; + + systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ]; +} diff --git a/machines/massicot/hardware-configuration.nix b/machines/massicot/hardware-configuration.nix new file mode 100644 index 0000000..89358f7 --- /dev/null +++ b/machines/massicot/hardware-configuration.nix @@ -0,0 +1,13 @@ +{ modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + boot.loader.grub = { + efiSupport = true; + device = "nodev"; + }; + fileSystems."/boot" = { device = "/dev/disk/by-uuid/AC27-D9D6"; fsType = "vfat"; }; + boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "xen_blkfront" ]; + boot.initrd.kernelModules = [ "nvme" ]; + fileSystems."/" = { device = "/dev/sda1"; fsType = "ext4"; }; + +} diff --git a/machines/massicot/kanidm-provision.nix b/machines/massicot/kanidm-provision.nix new file mode 100644 index 0000000..71ca402 --- /dev/null +++ b/machines/massicot/kanidm-provision.nix @@ -0,0 +1,143 @@ +{ + enable = true; + autoRemove = true; + groups = { + forgejo-access = { + members = [ "xin" ]; + }; + forgejo-admin = { + members = [ "xin" ]; + }; + gts-users = { + members = [ "xin" ]; + }; + ocis-users = { + members = [ "xin" ]; + }; + linux_users = { + members = [ "xin" ]; + }; + hedgedoc-users = { + members = [ "xin" ]; + }; + immich-users = { + members = [ "xin" "zhuo" "ycm" ]; + }; + grafana-superadmins = { + members = [ "xin" ]; + }; + grafana-admins = { + members = [ "xin" ]; + }; + grafana-editors = { + members = [ "xin" ]; + }; + grafana-users = { + members = [ "xin" ]; + }; + miniflux-users = { + members = [ "xin" ]; + }; + idm_people_self_mail_write = { + members = [ ]; + }; + }; + persons = { + xin = { + displayName = "Xinyang Li"; + mailAddresses = [ "lixinyang411@gmail.com" ]; + }; + + zhuo = { + displayName = "Zhuo"; + mailAddresses = [ "13681104320@163.com" ]; + }; + + ycm = { + displayName = "Chunming"; + mailAddresses = [ "chunmingyou@gmail.com" ]; + }; + }; + systems.oauth2 = { + forgejo = { + displayName = "ForgeJo"; + originUrl = "https://git.xinyang.life/"; + originLanding = "https://git.xinyang.life/user/oauth2/kandim"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + forgejo-access = [ "openid" "email" "profile" "groups" ]; + }; + claimMaps = { + forgejo_role = { + joinType = "array"; + valuesByGroup = { + forgejo-access = [ "Access" ]; + forgejo-admin = [ "Admin" ]; + }; + }; + }; + }; + gts = { + displayName = "GoToSocial"; + originUrl = "https://xinyang.life/"; + originLanding = "https://xinyang.life/"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + gts-users = [ "openid" "email" "profile" "groups" ]; + }; + }; + owncloud = { + displayName = "ownCloud"; + originUrl = "https://home.xinyang.life:9201/"; + originLanding = "https://home.xinyang.life:9201/"; + public = true; + scopeMaps = { + ocis-users = [ "openid" "email" "profile" ]; + }; + }; + hedgedoc = { + displayName = "HedgeDoc"; + originUrl = "https://docs.xinyang.life/"; + originLanding = "https://docs.xinyang.life/auth/oauth2"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + hedgedoc-users = [ "openid" "email" "profile" ]; + }; + }; + immich-mobile = { + displayName = "Immich"; + originUrl = "https://immich.xinyang.life:8000/api/oauth/mobile-redirect/"; + originLanding = "https://immich.xinyang.life:8000/api/oauth/mobile-redirect/"; + allowInsecureClientDisablePkce = true; + scopeMaps = { + immich-users = [ "openid" "email" "profile" ]; + }; + }; + miniflux = { + displayName = "Miniflux"; + originUrl = "https://rss.xinyang.life/"; + originLanding = "https://rss.xinyang.life/"; + scopeMaps = { + miniflux-users = [ "openid" "email" "profile" ]; + }; + }; + grafana = { + displayName = "Grafana"; + originUrl = "https://grafana.xinyang.life/"; + originLanding = "https://grafana.xinyang.life/"; + scopeMaps = { + grafana-users = [ "openid" "email" "profile" "groups" ]; + }; + claimMaps = { + grafana_role = { + joinType = "array"; + valuesByGroup = { + grafana-superadmins = [ "GrafanaAdmin" ]; + grafana-admins = [ "Admin" ]; + grafana-editors = [ "Editor" ]; + }; + }; + }; + }; + }; +} diff --git a/machines/massicot/networking.nix b/machines/massicot/networking.nix new file mode 100644 index 0000000..9588be9 --- /dev/null +++ b/machines/massicot/networking.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: { + networking = { + interfaces = { + eth0.useDHCP = true; + eth0.ipv6.addresses = [{ + address = "2a01:4f8:c17:345f::1"; + prefixLength = 64; + }]; + }; + defaultGateway6 = { + address = "fe80::1"; + interface = "eth0"; + }; + nameservers = [ ]; + }; +} diff --git a/machines/massicot/secrets.yaml b/machines/massicot/secrets.yaml new file mode 100644 index 0000000..cc3fd7f --- /dev/null +++ b/machines/massicot/secrets.yaml @@ -0,0 +1,37 @@ +storage_box_mount: ENC[AES256_GCM,data:9lOAL3tkfB0pN4/cuM4SX0xoMrW0UUEzTN8spw3MQ3BWrfsRc3Stsce3puXz1sRf,iv:7Q9wzpBgQ3tqcfy0n/c6Ya84Kg60nhR/e2H0pVntWsY=,tag:9a0xvNBGQpCvhxgmV3hrww==,type:str] +gts_env: ENC[AES256_GCM,data:StggMdJPevrDbrVDrBDETdQYnSOaTESkgSqpGKrSHXhS21nyCE5ya7/X4l0GVTXoGCyfWG7vK+PDW22mJxpYcj2CBaVUYDu/,iv:2fqWDaWAWxTXdG7w5HU6jBcappFEByNtYs0Jd6PaYnA=,tag:KGhrMemao6g4FkEAZmmacg==,type:str] +hedgedoc_env: ENC[AES256_GCM,data:zwAA+zKSJT0tZyYArCaa1lfL0y8DNHDp/thS11DrVxNvjmk38o0ydsKArfZKzFYye+qNBzz1B4sPCdW4cFgQUNgbM+n9AvoMB8CssdmQ+sALKmozA5aEV23q+khZSGlHocP6WA==,iv:SgZruOS1nanK64Ex1dvgoD1HzbGbNa4DFSBuVoaNgEc=,tag:R+I8m1AloDCXs5PdpEpS0w==,type:str] +grafana_oauth_secret: ENC[AES256_GCM,data:43+EBnN912eK/08MdJokWPxi2Lxn/D4hSHPhNmHOk9awWQ7ut/el0vaAa+Epqnui3le2p4VuotQT6XlIuDLrixIomrc6Qw5HERAEdZmbrGvDlrrNhw==,iv:Pfn8rL0LtG3hym9EdSZRjaPLMlWlut/nt2FEtRWnULo=,tag:moDWqF3aBbnO4aG0Cysfcw==,type:str] +miniflux: + oauth2_secret: ENC[AES256_GCM,data:jcZR9E9jXNKfkAoGgBI19qQeaz26R6qiAWjP4XrftHSCQV974tjJl+fiU8Xgi0bViA==,iv:/aY0bL/oAAHBhohy3FHB/UEDYryw7A7JOKvEbLtDHJg=,tag:Fn/6NurNkRphXySR+y9S9Q==,type:str] +forgejo: + env: ENC[AES256_GCM,data:TMeguXfanISeyvsay9SBqm3SSGKpp5nCkqhHblf0QHNzHWGQKwpORmWfOtVfgOh9qdDqq8wYBpXznmbvixjV,iv:IR/rMoAIvZCw9FURmau4+g8c3pvI9BRs7v1NJ5ia4jI=,tag:kjwf6RN5HN8I2sUhDcr4UQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1aGRvUUtjcDU2bnhaNDJD + K3c5TnFJeHQzM2VpeHphR2dGeS9NYzcyYjJnCnNrQ3dxL1hqR2MyQXhldUZ1VEJp + N25nVHZ1QjRydW9hTWE5d0x2M2pPNkkKLS0tIFpiRW8rZ1Q1R1RCZGN1ZGs3ek45 + UENaRjJPWFJqUlpzd3dHSC9pdnZ6STQKQaaY28FYUk3O9TTkX9LQTzlrqZVojgxY + M+N6LApfdoioQCmXduDbj18i0eUbECTBXR/uEFEIHbn6AJVD/vx7iw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1jle2auermhswqtehww9gqada8car5aczrx43ztzqf9wtcld0sfmqzaecta + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRY0lIeE9tWDA3Q21IWk1E + YnlaQUJybFB2bmFpbG1UZ0UyNG16WkRkZlNVCmUySHVBcXpWekpVN3R5dGs5ODY1 + V1ZlUk4zRSs1NkVjY3JSMVVQSXJ1OEkKLS0tIFMzeUNaYVpoNnV3TE1oamEwTEo2 + dnFBa0lDWWZtS1BHdzBoVzNTaGNkSEEKi/W1n7RT8NpTp00SBMwxsUJAPDhumJ/i + V2VnaSNwouD3SswTcoBzqQpBP9XrqzjIYGke90ZODFQbMY9WDQ+O0g== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-08-21T05:54:31Z" + mac: ENC[AES256_GCM,data:oNBabsDRuHjMBXynr8ytCLmv5NPyA0mRUcPJfFZjjAb9ZbGP+pquwJT3S0l2yo4Nsd0YQP8X1pGS3PEv9v+N538bxmMJJCERR7iZ5U5G4h0AvKi+UkjkveDdhPWBXhC1O+Up7reT/LLzOiZ1WUHCYRQfcb9R1RL3G2NpeYuOShk=,iv:FLmtKyZjZuGDnMjOgJdoIU9EXLQSZavs8f4q2C+Sxbk=,tag:sGoJNppCTYxZ2u2l0eMHgg==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.0 diff --git a/machines/massicot/services.nix b/machines/massicot/services.nix new file mode 100644 index 0000000..3137765 --- /dev/null +++ b/machines/massicot/services.nix @@ -0,0 +1,299 @@ +{ config, pkgs, lib, ... }: +let + kanidm_listen_port = 5324; +in +{ + networking.firewall.allowedTCPPorts = [ 80 443 2222 8448 ]; + networking.firewall.allowedUDPPorts = [ 80 443 8448 ]; + + custom.vaultwarden = { + enable = true; + domain = "vaultwarden.xinyang.life"; + }; + + custom.hedgedoc = { + enable = true; + caddy = true; + domain = "docs.xinyang.life"; + mediaPath = "/mnt/storage/hedgedoc"; + oidc = { + enable = true; + baseURL = "https://auth.xinyang.life/oauth2/openid/hedgedoc"; + authorizationURL = "https://auth.xinyang.life/ui/oauth2"; + tokenURL = "https://auth.xinyang.life/oauth2/token"; + userProfileURL = "https://auth.xinyang.life/oauth2/openid/hedgedoc/userinfo"; + }; + environmentFile = config.sops.secrets.hedgedoc_env.path; + }; + + custom.prometheus = { + enable = true; + exporters.blackbox.enable = true; + exporters.miniflux.enable = true; + }; + + systemd.mounts = map + (share: { + what = "//u380335-sub1.your-storagebox.de/u380335-sub1/${share}"; + where = "/mnt/storage/${share}"; + type = "cifs"; + options = "rw,uid=${share},gid=${share},credentials=${config.sops.secrets.storage_box_mount.path},_netdev,fsc"; + before = [ "${share}.service" ]; + after = [ "cachefilesd.service" ]; + wantedBy = [ "${share}.service" ]; + }) [ "forgejo" "gotosocial" "conduit" "hedgedoc" ]; + + services.cachefilesd.enable = true; + + system.activationScripts = { + conduit-media-link.text = '' + mkdir -m 700 -p /var/lib/private/matrix-conduit/media + chown conduit:conduit /var/lib/private/matrix-conduit/media + mount --bind --verbose /mnt/storage/conduit/media /var/lib/private/matrix-conduit/media + ''; + }; + security.acme = { + acceptTerms = true; + certs."auth.xinyang.life" = { + email = "lixinyang411@gmail.com"; + listenHTTP = "127.0.0.1:1360"; + group = "kanidm"; + }; + }; + + services.ntfy-sh = { + enable = true; + group = "caddy"; + settings = { + listen-unix = "/var/run/ntfy-sh/ntfy.sock"; + listen-unix-mode = 432; # octal 0660 + base-url = "https://ntfy.xinyang.life"; + }; + }; + + systemd.services.ntfy-sh.serviceConfig.RuntimeDirectory = "ntfy-sh"; + + services.kanidm = { + package = pkgs.kanidm.withSecretProvisioning; + enableServer = true; + serverSettings = { + domain = "auth.xinyang.life"; + origin = "https://auth.xinyang.life"; + bindaddress = "[::]:${toString kanidm_listen_port}"; + tls_key = ''${config.security.acme.certs."auth.xinyang.life".directory}/key.pem''; + tls_chain = ''${config.security.acme.certs."auth.xinyang.life".directory}/fullchain.pem''; + # db_path = "/var/lib/kanidm/kanidm.db"; + }; + provision = import ./kanidm-provision.nix; + }; + + custom.miniflux = { + enable = true; + environment = { + LOG_LEVEL = "debug"; + LISTEN_ADDR = "127.0.0.1:58173"; + BASE_URL = "https://rss.xinyang.life/"; + OAUTH2_PROVIDER = "oidc"; + OAUTH2_CLIENT_ID = "miniflux"; + OAUTH2_REDIRECT_URL = "https://rss.xinyang.life/oauth2/oidc/callback"; + OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://auth.xinyang.life/oauth2/openid/miniflux"; + OAUTH2_USER_CREATION = 1; + }; + oauth2SecretFile = config.sops.secrets."miniflux/oauth2_secret".path; + }; + + services.matrix-conduit = { + enable = true; + # package = inputs.conduit.packages.${pkgs.system}.default; + package = pkgs.matrix-conduit; + settings.global = { + server_name = "xinyang.life"; + port = 6167; + # database_path = "/var/lib/matrix-conduit/"; + max_concurrent_requests = 100; + log = "info"; + database_backend = "rocksdb"; + allow_registration = false; + + well_known = { + client = "https://msg.xinyang.life"; + server = "msg.xinyang.life:443"; + }; + }; + }; + + services.gotosocial = { + enable = true; + settings = { + log-level = "debug"; + host = "xinyang.life"; + letsencrypt-enabled = false; + bind-address = "localhost"; + instance-expose-public-timeline = true; + oidc-enabled = true; + oidc-idp-name = "Kanidm"; + oidc-issuer = "https://auth.xinyang.life/oauth2/openid/gts"; + oidc-client-id = "gts"; + oidc-link-existing = true; + storage-local-base-path = "/mnt/storage/gotosocial/storage"; + }; + environmentFile = config.sops.secrets.gts_env.path; + }; + + services.forgejo = { + enable = true; + # Use cutting edge instead of lts + package = pkgs.forgejo; + repositoryRoot = "/mnt/storage/forgejo/repositories"; + lfs = { + enable = true; + contentDir = "/mnt/storage/forgejo/lfs"; + }; + settings = { + service.DISABLE_REGISTRATION = true; + server = { + ROOT_URL = "https://git.xinyang.life/"; + START_SSH_SERVER = false; + SSH_USER = config.services.forgejo.user; + SSH_DOMAIN = "ssh.xinyang.life"; + SSH_PORT = 22; + LFS_MAX_FILE_SIZE = 10737418240; + LANDING_PAGE = "/explore/repos"; + }; + repository = { + ENABLE_PUSH_CREATE_USER = true; + }; + service = { + ENABLE_BASIC_AUTHENTICATION = false; + }; + oauth2 = { + ENABLED = false; # Disable forgejo as oauth2 provider + }; + oauth2_client = { + ACCOUNT_LINKING = "auto"; + USERNAME = "email"; + ENABLE_AUTO_REGISTRATION = true; + UPDATE_AVATAR = false; + OPENID_CONNECT_SCOPES = "openid profile email groups"; + }; + other = { + SHOW_FOOTER_VERSION = false; + }; + }; + }; + + systemd.services.forgejo = { + serviceConfig = { + EnvironmentFile = config.sops.secrets."forgejo/env".path; + ExecStartPost = '' + ${lib.getExe config.services.forgejo.package} admin auth update-oauth \ + --id 1 \ + --name kanidm \ + --provider openidConnect \ + --key forgejo \ + --secret $CLIENT_SECRET \ + --icon-url https://auth.xinyang.life/pkg/img/favicon.png \ + --group-claim-name forgejo_role --admin-group Admin + ''; + }; + }; + + services.grafana = { + enable = true; + settings = { + server = { + http_addr = "127.0.0.1"; + http_port = 3003; + root_url = "https://grafana.xinyang.life"; + domain = "grafana.xinyang.life"; + }; + "auth.generic_oauth" = { + enabled = true; + name = "Kanidm"; + client_id = "grafana"; + scopes = "openid,profile,email,groups"; + auth_url = "https://auth.xinyang.life/ui/oauth2"; + token_url = "https://auth.xinyang.life/oauth2/token"; + api_url = "https://auth.xinyang.life/oauth2/openid/grafana/userinfo"; + use_pkce = true; + use_refresh_token = true; + allow_sign_up = true; + login_attribute_path = "preferred_username"; + groups_attribute_path = "groups"; + role_attribute_path = "contains(grafana_role[*], 'GrafanaAdmin') && 'GrafanaAdmin' || contains(grafana_role[*], 'Admin') && 'Admin' || contains(grafana_role[*], 'Editor') && 'Editor' || 'Viewer'"; + allow_assign_grafana_admin = true; + auto_login = true; + }; + "auth" = { disable_login_form = true; }; + }; + }; + + systemd.services.grafana.serviceConfig.EnvironmentFile = config.sops.secrets.grafana_oauth_secret.path; + + users.users.git = { + isSystemUser = true; + useDefaultShell = true; + group = "git"; + extraGroups = [ "forgejo" ]; + }; + users.groups.git = { }; + + users.users = { + ${config.services.caddy.user}.extraGroups = [ + config.services.ntfy-sh.group + ]; + }; + + services.caddy = { + enable = true; + virtualHosts."xinyang.life:443".extraConfig = '' + tls internal + encode zstd gzip + reverse_proxy /.well-known/matrix/* localhost:6167 + reverse_proxy * http://localhost:8080 { + flush_interval -1 + } + ''; + virtualHosts."https://msg.xinyang.life:443".extraConfig = '' + reverse_proxy /_matrix/* localhost:6167 + ''; + virtualHosts."https://git.xinyang.life:443".extraConfig = '' + reverse_proxy http://${config.services.gitea.settings.server.DOMAIN}:${toString config.services.gitea.settings.server.HTTP_PORT} + ''; + + virtualHosts."http://auth.xinyang.life:80".extraConfig = '' + reverse_proxy ${config.security.acme.certs."auth.xinyang.life".listenHTTP} + ''; + virtualHosts."https://auth.xinyang.life".extraConfig = '' + reverse_proxy https://127.0.0.1:${toString kanidm_listen_port} { + header_up Host {upstream_hostport} + header_down Access-Control-Allow-Origin "*" + transport http { + tls_server_name ${config.services.kanidm.serverSettings.domain} + } + } + ''; + + virtualHosts."https://rss.xinyang.life".extraConfig = '' + reverse_proxy ${config.custom.miniflux.environment.LISTEN_ADDR} + ''; + + virtualHosts."https://ntfy.xinyang.life".extraConfig = '' + reverse_proxy unix/${config.services.ntfy-sh.settings.listen-unix} + @httpget { + protocol http + method GET + path_regexp ^/([-_a-z0-9]{0,64}$|docs/|static/) + } + redir @httpget https://{host}{uri} + ''; + + virtualHosts."https://grafana.xinyang.life".extraConfig = + let + grafanaSettings = config.services.grafana.settings.server; + in + '' + reverse_proxy http://${grafanaSettings.http_addr}:${toString grafanaSettings.http_port} + ''; + }; +} diff --git a/machines/netdrives.nix b/machines/netdrives.nix new file mode 100644 index 0000000..8092196 --- /dev/null +++ b/machines/netdrives.nix @@ -0,0 +1,22 @@ +{ pkgs, config, ... }: +{ + sops.secrets = { + autofs-nas = { + owner = "davfs2"; + }; + autofs-nas-secret = { + path = "/etc/davfs2/secrets"; + }; + }; + fileSystems."/media/nas" = { + device = "https://home.xinyang.life:5244/dav"; + fsType = "davfs"; + options = [ + "uid=1000" + "gid=1000" + "rw" + "_netdev" + ]; + + }; +} \ No newline at end of file diff --git a/machines/raspite/configuration.nix b/machines/raspite/configuration.nix new file mode 100644 index 0000000..71bc747 --- /dev/null +++ b/machines/raspite/configuration.nix @@ -0,0 +1,55 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ./hass.nix + ]; + + commonSettings.nix.enableMirrors = true; + + nixpkgs.overlays = [ + # Workaround https://github.com/NixOS/nixpkgs/issues/126755#issuecomment-869149243 + (final: super: { + makeModulesClosure = x: + super.makeModulesClosure (x // { allowMissing = true; }); + }) + ]; + + environment.systemPackages = with pkgs; [ + git + libraspberrypi + raspberrypi-eeprom + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "raspite"; + useDHCP = false; + interfaces.eth0.useDHCP = true; + }; + + # boot.kernelPackages = pkgs.linuxPackages_stable; + + custom.kanidm-client = { + enable = true; + uri = "https://auth.xinyang.life"; + asSSHAuth = { + enable = true; + allowedGroups = [ "linux_users" ]; + hardening = true; + }; + sudoers = [ "xin@auth.xinyang.life" ]; + }; + + security.sudo = { + execWheelOnly = true; + wheelNeedsPassword = false; + }; + + # fileSystems."/".fsType = lib.mkForce "btrfs"; + boot.supportedFilesystems.zfs = lib.mkForce false; + + services.dae.enable = false; + services.dae.configFile = "/var/lib/dae/config.dae"; +} diff --git a/machines/raspite/hass.nix b/machines/raspite/hass.nix new file mode 100644 index 0000000..8482129 --- /dev/null +++ b/machines/raspite/hass.nix @@ -0,0 +1,50 @@ +{ config, pkgs, ... }: { + services.home-assistant = { + enable = true; + extraComponents = [ + "default_config" + "esphome" + "met" + "radio_browser" + ]; + openFirewall = false; + config = { + default_config = {}; + http = { + server_host = "::1"; + base_url = "raspite.local:1000"; + use_x_forward_for = true; + trusted_proxies = [ + "::1" + ]; + }; + }; + }; + + services.esphome = { + enable = true; + openFirewall = false; + }; + + users.groups.dialout.members = config.users.groups.wheel.members; + + environment.systemPackages = with pkgs; [ + zigbee2mqtt + ]; + + networking.firewall.allowedTCPPorts = [ 1000 1001 ]; + + services.caddy = { + enable = true; + virtualHosts = { + # reverse_proxy ${config.services.home-assistant.config.http.server_host}:${toString config.services.home-assistant.config.http.server_port} + "raspite.local:1000".extraConfig = '' + reverse_proxy http://[::1]:8123 + ''; + + "raspite.local:1001".extraConfig = '' + reverse_proxy ${config.services.esphome.address}:${toString config.services.esphome.port} + ''; + }; + }; +} diff --git a/machines/raspite/secrets.yaml b/machines/raspite/secrets.yaml new file mode 100644 index 0000000..fcb790e --- /dev/null +++ b/machines/raspite/secrets.yaml @@ -0,0 +1,30 @@ +password: ENC[AES256_GCM,data:QHPNTvjNjrcUaV7aVvnFQFF+1bA+g1Y2emYIabBgHQ7Dmg7SuOwVpBsZCvsh+BgrWLykK3Gcf+huTMzixjaqXbGHrpqx9Eq9wi1O1alVG8bJ/UvWr7H3qBCuye85KUopBxXLF93skT7H1Q==,iv:Iq/s+AuMJN/Z/Pbc5UsZQA6gvnPXxihKJzWYl+N6Gmc=,tag:6UvNTQlLrl1ay3BI6vPqTw==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBieXZQcFZ6R0ZBQUdTMWtL + QXM2djdBNThrNnpuT1lpNDU1R3NIM2FRNnhZCkZqbUtrWldFMS9oOTE3T2ZCTklm + emxsL21pQThiMDJIUXA1Y0RKSVBRWFUKLS0tIE1qK0dySHZHUVZ1aDZoZ1lEZHoy + dnBLOWV4NjBrZzM5VkhRZFFrNFByVFkKK7j/rDiD7WbCU/Z1+FRuxjOitS6Y9cc1 + L2oW35AJluG27tdwe39nBORzeLwDrcFy5TpUSV9hMEBbeDBlhLNSiA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1nugzw24upk8pz5lyz2z89qk8se4gpcsg3ypcs58nykncr56sevrsm8qpvj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPb0RxTHFhZjZ5bEtpblo1 + VHJkeDFpNjhoc294eWs5TmxxcEMwOTQ4SmxVCmp1dnFXSlNiUzdtWm9WSmlMa3BR + RDFmWVdxcXJzRmdzbzVOMkUvNDd4Y1UKLS0tIDVkNHBrYWFmNWtkNllidUlPdFJ1 + djhXQ2RzM0JEdnRvUkxVNm9MdFNJUHMKmacD8MIV7r92c5KbJtg7CbnI09QMclQl + 5rIF5vcgaRRpS6zXq22OgxSjsjIHg7jDOkUJdueGNHzc4f9F91+0yQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-04-23T03:02:43Z" + mac: ENC[AES256_GCM,data:7k+Eoua6DviF6XN5QiVOXE4LHr0gggvvYY9EMBU4J6RsA9hzi0L3DjdofppAvG2928mCd/SYiZC3vGU8UFohXbZuxFLq9YJGkE1P+VxvlggkMKoJkIbE2d2t78zm2gt4nd60tDyJgYINqbbgfs2qOdnm8Y/WShRkmNs/ggf5Azo=,iv:cXoP6GYOzhfXov/l9rSg/2GIGI4aeJonAXCQ6k6YuaQ=,tag:Tv/JYpj6DfhddSzSkh8zcQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/machines/secrets.yaml b/machines/secrets.yaml new file mode 100644 index 0000000..dec3d21 --- /dev/null +++ b/machines/secrets.yaml @@ -0,0 +1,84 @@ +clash_subscription_link: ENC[AES256_GCM,data:Vwy0c8gOeR1XG/QNp8TGuBe/5kezD7SSStN/iCnihbbJYW78LNfPfvmVAEXjQlf5Ycts2Cb2JHGtWp3rmQQtWBx8LfIewqhNDk9fCywqIv7uSmqVpJNTHfYhjpF6PLvtz51VfTKph+fplZ9dMu23P9g7Wn6dzVizo8DX6xHWN2jDyHza5zkiNrzbmiaLwbLu1dAzvNSI67A=,iv:pZ189IPPCBjscXzEdgQCRdFlls3TniwDfNCd+H1FFaQ=,tag:dpt+3kdx8m1f0X0SHm+ATA==,type:str] +autofs-nas: ENC[AES256_GCM,data:wcrA2t8/i9PaxA1PQ3CDVJZUhVchGV4vCfa5j/ReNahKV3cfDf2owbpeB827sMpjYyyvSH6nri7mra/BLMAPcgySCpZNAgdR9DQZXAQ=,iv:QJzsS5a6vWeoBxkB13yXdVbyn0tt2QTvqj0LaHn6S2g=,tag:TtgubLgWBBzl67MVal5BvQ==,type:str] +autofs-nas-secret: ENC[AES256_GCM,data:OBh8h5CFv1Z4G6bMesna4zmXNASKhYdjFBvg47T9aKBCLDp/xVWnnQj8N7AFGg49wJ+0gYuqb33lIqpSnQ==,iv:UCaGeE8j4RqJzA0xhu3oB2xvzombzQD3fjLKCWd5fDg=,tag:+Oc78ddpLH7R2aT7gW3Ouw==,type:str] +github_public_token: ENC[AES256_GCM,data:AmAfmq5mDGxmHUUlGzD7k50jRTCcnZqqFdYdrMtYysmw6FUjPc1YgsEVNqHOjiEMYbr8Gs+wjVu8BYIuh1wuDzOOfE+ejIbosrOtK4dCapmIzZFlRiK/AyrUCm2qDWUObhJDPMJN4px947VFJ5to5GLifGEXdUGm,iv:PJSFtJBelyc3rzd6hqjMp+ciU2Q3FTOEXsiq5F2KKTY=,tag:MjrTl+4+8SZeBDJpUJtsiw==,type:str] +singbox_sg_server: ENC[AES256_GCM,data:5rogqKm5yiy5Yvz4Vo1a6Q==,iv:Vx9wNTdVHkReux4YeQY+0VkC1Wqg/CRkY7frVY/3e50=,tag:9fVlCP/DadcOvhO3c1oCzw==,type:str] +singbox_jp_server: ENC[AES256_GCM,data:xKTcxkcu1WIsT/wlMpEoqGJK,iv:nXetY339YuOi2jFEb3xkPTglHRMk/quIrQL4ko+8MxY=,tag:+Nwsx65/gdrDhL1ZurR5Ng==,type:str] +singbox_password: ENC[AES256_GCM,data:0tBIzwtNSQqbGlD+CDnQfJigbFVBChEL,iv:W2HaHeSkvmS6jHSnfOJ6tD2QXuUq1A+mfZf7sEXB++E=,tag:5BtYAv1NO70IL4m/uG8QKA==,type:str] +singbox_uuid: ENC[AES256_GCM,data:ufN+vDl/rDASoQL23tHwlr3ybMyrlC/Kd7bT0c5+SP+bc6Zj,iv:+uwt/N9LpFaJK6MjoczyrZ039MDZn4kRmtEoq4OvdFU=,tag:6Yma9+yrISwQoSRDgUbuwA==,type:str] +grafana_cloud_api: ENC[AES256_GCM,data:Pz+tE09dcJa+ZEWS3vtpOtitGCA9Cg/+gOd/0FsF8ooxzPyN9/UMuTcP02aIPW5v7yZCkGJOAXufIyechNf0crgAV/KmwGGwixH7I+1f3sDtGiFZEMnQgrysyfJo0KIrIZ8XP0SyXDs3vKjDU8cUI4+IyucHacWQ1kWdEtINjcPNHRPS2yaMUIvsRn0z8Cs2byMD3ghUHHHOz40CuO6r4A==,iv:cHvbeCmLFmJPNKsl1BBYx9WJP7ZJWi+8c9yHZWc6FTs=,tag:yWXtPokYE4frCmzzzyEqEg==,type:str] +private_dns_address: ENC[AES256_GCM,data:m/u3oc+6ef8dLa7Dpu+5T9TTSdXqJjS9ecA+sPj0r8qX06+QgiQnpmEW4w==,iv:8+qG5rQXAKfrykEjt9qrbtyNaBuKvi7EaIWouRqEipY=,tag:XlMccTKL239/NnAprtqYrg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMdjlhNVZpUjYzRTVXNG9Y + S0lEUVdoM003YVZoeXYyOXdwY3Rla3VJSkZvCkl0a3FPeVpMY1JTWkdCb3NaeVBQ + dHVSVzg1cDNIS3JnMmYxbUlzbjFicG8KLS0tIHFENDNaZENzSzJQZDVLSVJ5VHBP + aVpJN1dkbEQ2djQyWVdRTUx4NGdaaTgKgfcGovmMgVFHkPLHT7C5bg75LXg8MFK0 + s8IL8qhHif4uzMuFjdw9MzyuQc1bqGzazX5YC1MYLYCOWHRlLq9mXw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1ytwfqfeez3dqtazyjltn7mznccwx3ua8djhned7n8mxqhw4p6e5s97skfa + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWQXdMdzMxNzE3SHpZR09w + OTFtNzJLdVk5bWlyNGl4RzA4NWFUQTlvbUQ4ClhGZHI3ekJWYnNwamJXWWVtc3do + TXpoWERqT24rMjRtQUJUb2RKSm9BUjQKLS0tIHd6QXUrWVJ5aU52VEtDL01Kd2d2 + V3U4cTNoVzYzdmt5YkpNUmsyUWtCaEkKhxEQVVt2zvVGFGtlfPr0sQ7b0yUDRDOV + CN8nxyO0NiuvEKSkw+KCkcNWNQZDnHTQ3pwWyAohRZk3vB/RSuApCg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1nugzw24upk8pz5lyz2z89qk8se4gpcsg3ypcs58nykncr56sevrsm8qpvj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsdlh1Kyt4KzlFR2RkTmFo + S00zK1RDNnJwVzQ4Um93TDBEcnJZUjJLUG00CjloMFdaNm5LU2lRRVpnM0RpN3BR + Ly9pUkxuZHd3NHJRSG1Ha3ZVcE50RkUKLS0tIDN1K0xnb01EL2Q3aG5RV0grdmdl + TWh3ZStZQ3lNYkh2cjJ1RWhLRDJ0KzQK/+R6hFg8ErtT/rkSOCwRdArTPIE/J9Yv + 2qZmREM7q99L5w6lEBTn9SRekowk0ncwIoTxRfn576wyl++b8gBv9Q== + -----END AGE ENCRYPTED FILE----- + - recipient: age13s6rwd3wjk2x5wkn69tdczhl3l5d7mfmlv90efsv4q67jne43qss9tcakx + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJelptN09Oa0NRdTFER2du + clZGM09uMlhpMlZDQ2VvTTZOZ09VWGNwaWpjCmRuMjM3VTRpT3hRaWpEYW5HaWRr + K2pEM3dLYjhSS25hSUtrYkRvYXpCd2MKLS0tIHU2eDlXdVBlZUFTMjYxRTladVJV + cjZ0dGtmM29YdXI5Z1RpVVdRSktBU2MKdR5d6fb2EHX5j51qE5gg0GXKjy4fCpT0 + Q+fZslCPDZqaOX/9kGT874TuW4CC1wttpsCDNIEzrX54SvIGfsVPgg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1t5nw2jx4dw67jkf72uxcxt72j7lq3xyj35lvl09f8kala90h2g2s2a5yvj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmRUhOaVhSMFJFcC9qYytK + dHJ1ZUg1SWRBeTVSeFhDRW1VbG1HWUJaUEhvCnBOaENFUXlJWHAxQ0ZGVGFxQkpC + b3dwb0VJVTR1MUNDT3VQR0tsNE5vUDQKLS0tIEJkbWN5MWRtKzRveldvT2dMR2k1 + djdBQzNvSFNPRDZwN1B1dG5sUzlRdzgK35bNxRGDQw+dtnXcXSXk67kJFce52vqn + srABR9FOYmSfesLKXOdKItLAGffkfB7kuiXO7CvyVTkgJOjBgK6Tnw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1fw2sqaa5s9c8ml6ncsexkj8ar4288387ju92ytjys4awf9aw6smqqz94dh + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNb2JOOUlGL1pCVXVYZk1j + cWg0NE13WnBUWDA4VTNRdlNmWktRN0lJbkVBCkpHTklwbnFsd0NBOTY5V0JCTVJN + alVFeW41ajlZR2dHZDlrL2FtazB6QU0KLS0tIDhoTXppS0lnZmFJY1lhSDBudVB4 + NHFLdnorOUtJSzVPWldYakppZFJwdlEKbZnT7m6R7H/yLG+tDbQECgQVGX0xT4jC + 67z8k6xbnsT2srhhXk/NHi+/j7AcHhPG6cTO1z8MrxkMikk8ihU1Iw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1jle2auermhswqtehww9gqada8car5aczrx43ztzqf9wtcld0sfmqzaecta + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIaHFOa1ArRW5xWFAyWXlh + enpQUzZKbFFFUzN1cisrd2JGelpXSWppRnhvCmY5VDlSTFhJakt3aU8zYjRrZXVQ + b3o2NlpCeGZZU1ROeW5XOFVpdEZnZXcKLS0tIGZ5M2IxNHp0Qm8rckROdy96a0pG + NjVEaWN3cU1rRjQ2a29wV1g1NzE0UTAKNefzj+p+U735LHqm5lnWGHCARuqvFmgA + 6bxJN9frAMZQIXZSwOTrfpYrTmKcBLcfWxq7LUPluw9HinQnkFpWqg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-07-17T03:43:42Z" + mac: ENC[AES256_GCM,data:5dnJSeY8lZrIo/bl8MECwmaQo+fQ+BEun9BQ7tFHUo1lzk4wn2N1RuPMuPLPE1wARfOJR2lUyh+o3froFqQT6EGDhA68ETHxm+NqxbstouK+pSu0WJzg7ImuAuzd8B81xXBTQj6umOZy6oRsgvAYo2C8aEfzs19+kYrAM4bXo7k=,iv:YvtOVDD347fCFvqyTljHOQm6ewSR01WlYVBNVdm/BNc=,tag:r/HzESO6csxzLJMHTRC7bA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.0 diff --git a/machines/sops.nix b/machines/sops.nix new file mode 100644 index 0000000..de0cf5b --- /dev/null +++ b/machines/sops.nix @@ -0,0 +1,34 @@ +{ inputs, config, lib, ... }: +{ + imports = [ inputs.sops-nix.nixosModules.sops ]; + config = { + sops = { + defaultSopsFile = ./secrets.yaml; + # TODO: How to generate this key when bootstrap? + age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + secrets = { + github_public_token = { + owner = "root"; + }; + singbox_sg_server = { + owner = "root"; + }; + singbox_jp_server = { + owner = "root"; + }; + singbox_password = { + owner = "root"; + }; + singbox_uuid = { + owner = "root"; + }; + private_dns_address = { + owner = "root"; + }; + }; + secrets.grafana_cloud_api = lib.mkIf config.services.prometheus.enable { + owner = "prometheus"; + }; + }; + }; +} diff --git a/machines/weilite/default.nix b/machines/weilite/default.nix new file mode 100644 index 0000000..0ad8822 --- /dev/null +++ b/machines/weilite/default.nix @@ -0,0 +1,132 @@ +{ inputs, config, pkgs, lib, modulesPath, ... }: + +with lib; + +{ + imports = [ + inputs.sops-nix.nixosModules.sops + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + config = { + networking.hostName = "weilite"; + commonSettings = { + auth.enable = true; + nix = { + enable = true; + enableMirrors = true; + }; + }; + + boot = { + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ahci" "usb_storage" "sd_mod" ]; + kernelModules = [ "kvm-intel" ]; + }; + + environment.systemPackages = [ + pkgs.virtiofsd + ]; + + sops = { + defaultSopsFile = ./secrets.yaml; + age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + secrets = { + cloudflare_dns_token = { + owner = "caddy"; + mode = "400"; + }; + }; + }; + + custom.prometheus = { + enable = true; + }; + + systemd.mounts = [ + { what = "immich"; + where = "/mnt/XinPhotos/immich"; + type = "virtiofs"; + options = "rw"; + wantedBy = [ "immich-server.service" ]; + } + { what = "originals"; + where = "/mnt/XinPhotos/originals"; + type = "virtiofs"; + options = "ro,nodev,nosuid"; + wantedBy = [ "immich-server.service" ]; + } + ]; + + services.openssh.ports = [ 22 2222 ]; + + services.immich = { + enable = true; + mediaLocation = "/mnt/XinPhotos/immich"; + host = "127.0.0.1"; + port = 3001; + openFirewall = true; + machine-learning.enable = false; + environment = { + IMMICH_MACHINE_LEARNING_ENABLED = "false"; + }; + }; + + services.dae = { + enable = true; + configFile = "/var/lib/dae/config.dae"; + }; + + services.tailscale = { + enable = true; + openFirewall = true; + permitCertUid = "caddy"; + }; + + services.caddy = { + enable = true; + package = pkgs.caddy.withPlugins { + caddyModules = [ + { repo = "github.com/caddy-dns/cloudflare"; version = "89f16b99c18ef49c8bb470a82f895bce01cbaece"; } + ]; + vendorHash = "sha256-fTcMtg5GGEgclIwJCav0jjWpqT+nKw2OF1Ow0MEEitk="; + }; + virtualHosts."weilite.coho-tet.ts.net:8080".extraConfig = '' + reverse_proxy 127.0.0.1:${toString config.services.immich.port} + ''; + # API Token must be added in systemd environment file + virtualHosts."immich.xinyang.life:8000".extraConfig = '' + tls { + dns cloudflare {env.CLOUDFLARE_API_TOKEN} + } + reverse_proxy 127.0.0.1:${toString config.services.immich.port} + ''; + }; + + networking.firewall.allowedTCPPorts = [ 8000 ]; + + systemd.services.caddy = { + serviceConfig = { + EnvironmentFile = config.sops.secrets.cloudflare_dns_token.path; + }; + }; + + time.timeZone = "Asia/Shanghai"; + + fileSystems."/" = { + device = "/dev/disk/by-label/nixos"; + fsType = "btrfs"; + }; + + fileSystems."/boot" = { + device = "/dev/sda1"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + + system.stateVersion = "24.11"; + }; +} diff --git a/machines/weilite/secrets.yaml b/machines/weilite/secrets.yaml new file mode 100644 index 0000000..02f78d6 --- /dev/null +++ b/machines/weilite/secrets.yaml @@ -0,0 +1,30 @@ +cloudflare_dns_token: ENC[AES256_GCM,data:m4euSkxxJmiMk9UPyeni/hwpl1W9A4MM0ssg71eOBsX4fFyG39NJeKbNTddW7omBx3gKJtnrRuDdOj5wpg==,iv:eRVzsGwz8hWC42jM+VeSUWCS9Gi8VGSY8Fyh+En0jEI=,tag:NNE8VeNQ8kp9KyziVokyuQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1uw059wcwfvd9xuj0hpqzqpeg7qemecspjrsatg37wc7rs2pumfdsgken0c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtYkRNYmtjUkpoOXhRY1Yz + UkxnSEJiSXRvMy9WQWx5R1VHYVlnL1R2Tm1jCk8yUi80MG9kTWtSRndXRThuVThv + bERaUGwzaVJDem9IeFFIb2hiT1ZjTzQKLS0tIHo4bDJQa2dVbTl1aWxyYVd6bkl0 + c0g5TW03TU51L1hiSk95S05Eaks5TEEKBfA6XNAtcl7bKgDyVmuO6M45x9IJ7gqV + Nd+BvOK+iomEubZqsyMPLM3NfOL1dwSOnmwSdUZasUzuGCaw6IdlOA== + -----END AGE ENCRYPTED FILE----- + - recipient: age17r3fxfmt6hgwe984w4lds9u0cnkf5ttq8hnqt800ayfmx7t8t5gqjddyml + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBZlVTY1hhcC95RExJL1Jn + blBncWxlWmxsQS8vQ3dhd1pXR1VCbXltUEQ4ClE0NEZweERYK3cyelpDRjkrNlBH + RHBIQTI0M2pnNm5qdnorNWFmMmd0ZFUKLS0tIEE4cFVteUZjT04wbk1RSWlmOU1P + V0thRjU4WGpQRGFpcnoxSjZTZHhTTkUKzNMHh9p7GUY3hL5XZ9S4x20CwaItsXFV + RKujsFVVBd8Kuq/jyOCBTRCscuHI4LW/wYeZYHFEZFSTK2liAqspgw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-07-29T09:05:41Z" + mac: ENC[AES256_GCM,data:4RX5WtJnI4R2OAKNljo8IhBNTR+PSSFsT4rE0mjS4pEdWyJilAgLwcVU0DEDp7thHeT+YyjDQ9d3z1aeGALlJ3sV57azu4F9/KXixvZMKJtmFRsC74OTSBzFfnA4W9MjOTn95L+RQOJ/3UH1FAZ7UHAe3Os98kNW98D/Nv4S9us=,iv:En7RNovlF1yRURu9fGHRgWvsr3FzpeLtrKELtqkJUb8=,tag:4eVlLsraN17rBbAL7xOHnQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.9.0 diff --git a/modules/home-manager/alacritty.nix b/modules/home-manager/alacritty.nix new file mode 100644 index 0000000..b4b7c2a --- /dev/null +++ b/modules/home-manager/alacritty.nix @@ -0,0 +1,32 @@ +{ config, pkgs, lib, ... }: +with lib; + +let + cfg = config.custom-hm.alacritty; +in +{ + options.custom-hm.alacritty = { + enable = mkEnableOption "alacritty"; + }; + + config = mkIf cfg.enable { + programs.alacritty = { + enable = true; + settings = { + shell = { + program = config.programs.zellij.package + "/bin/zellij"; + args = [ + "attach" + "-c" + "alacritty-zellij" + ]; + }; + font.size = 10.0; + window = { + resize_increments = true; + dynamic_padding = true; + }; + }; + }; + }; +} diff --git a/modules/home-manager/default.nix b/modules/home-manager/default.nix new file mode 100644 index 0000000..14159ce --- /dev/null +++ b/modules/home-manager/default.nix @@ -0,0 +1,12 @@ +{ + imports = [ + ./alacritty.nix + ./direnv.nix + ./fish.nix + ./git.nix + ./tmux.nix + ./vim.nix + ./vscode.nix + ./zellij.nix + ]; +} diff --git a/modules/home-manager/direnv.nix b/modules/home-manager/direnv.nix new file mode 100644 index 0000000..46297b8 --- /dev/null +++ b/modules/home-manager/direnv.nix @@ -0,0 +1,30 @@ +{ config, lib, ... }: +with lib; + +let + cfg = config.custom-hm.direnv; + changeCacheDir = '' + declare -A direnv_layout_dirs + direnv_layout_dir() { + local hash path + echo "''${direnv_layout_dirs[$PWD]:=$( + hash="$(sha1sum - <<< "$PWD" | head -c40)" + path="''${PWD//[^a-zA-Z0-9]/-}" + echo "''${XDG_CACHE_HOME}/direnv/layouts/''${hash}''${path}" + )}" + } + ''; +in +{ + options.custom-hm.direnv = { + enable = mkEnableOption "direnv"; + }; + config = { + programs = mkIf cfg.enable { + direnv = { + enable = true; + stdlib = changeCacheDir; + }; + }; + }; +} diff --git a/modules/home-manager/fish.nix b/modules/home-manager/fish.nix new file mode 100644 index 0000000..927b69f --- /dev/null +++ b/modules/home-manager/fish.nix @@ -0,0 +1,72 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.custom-hm.fish; +in +{ + options.custom-hm.fish = { + enable = mkEnableOption "fish"; + plugins = mkOption { + type = types.listOf types.str; + default = [ "pisces" "done" "hydro" "grc" ]; + }; + functions = { + enable = mkOption { + type = types.bool; + default = true; + }; + }; + alias = { + enable = mkOption { + type = types.bool; + default = true; + }; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ pkgs.grc ]; + programs.fish = { + enable = true; + plugins = with pkgs; (filter ( + e: hasAttr e.name (builtins.listToAttrs # { "xxx" = true; } + (map (p: { name = p; value = true; }) cfg.plugins) # { name = "xxx"; value = true; } + )) [ + { name = "pisces"; + src = fishPlugins.pisces.src; + } + { name = "done"; + src = fishPlugins.done.src; + } + { name = "hydro"; + src = fishPlugins.hydro.src; + } + { name = "grc"; + src = fishPlugins.grc.src; + } + ]); + interactiveShellInit = let + extraInit = if cfg.functions.enable then '' + ${pkgs.nix-your-shell}/bin/nix-your-shell fish | source + function fish_right_prompt + if test -n "$IN_NIX_SHELL" + echo -n "" + else if test $SHLVL -ge 3 + echo -n "<🚀lv$SHLVL>" + end + end + function fish_command_not_found + ${pkgs.comma}/bin/comma $argv + end + '' else ""; + in '' + fish_config prompt choose arrow + '' + extraInit; + functions = mkIf cfg.functions.enable { + gitignore = "curl -sL https://www.gitignore.io/api/$argv"; + }; + }; + }; +} diff --git a/modules/home-manager/git.nix b/modules/home-manager/git.nix new file mode 100644 index 0000000..5b2bc63 --- /dev/null +++ b/modules/home-manager/git.nix @@ -0,0 +1,47 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.custom-hm.git; +in +{ + options.custom-hm.git = { + enable = mkEnableOption "Enable git configuration"; + signing = mkOption { + type = types.submodule { + options = { + enable = mkEnableOption "Git ssh signing"; + keyFile = mkOption { + type = types.str; + default = "~/.ssh/id_ecdsa.pub"; + }; + }; + }; + }; + }; + config = { + programs.git = mkIf cfg.enable { + enable = true; + delta.enable = true; + userName = "Xinyang Li"; + userEmail = "lixinyang411@gmail.com"; + aliases = { + graph = "log --all --oneline --graph --decorate"; + a = "add"; + d = "diff"; + s = "status"; + }; + signing = mkIf cfg.signing.enable { + signByDefault = true; + key = cfg.signing.keyFile; + }; + extraConfig.user = mkIf cfg.signing.enable { + signingkey = cfg.signing.keyFile; + }; + extraConfig.gpg = mkIf cfg.signing.enable { + format = "ssh"; + }; + }; + }; +} diff --git a/modules/home-manager/tmux.nix b/modules/home-manager/tmux.nix new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/modules/home-manager/tmux.nix @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/modules/home-manager/vim.nix b/modules/home-manager/vim.nix new file mode 100644 index 0000000..f66535f --- /dev/null +++ b/modules/home-manager/vim.nix @@ -0,0 +1,22 @@ +{ config, pkgs, lib, ... }: +let + inherit (lib) mkIf mkEnableOption getExe; + cfg = config.custom-hm.neovim; + tomlFormat = pkgs.formats.toml { }; + neovideConfig = { + neovim-bin = getExe pkgs.nixvim; + fork = true; + }; +in +{ + options.custom-hm.neovim = { + enable = mkEnableOption "neovim configurations"; + }; + config = mkIf cfg.enable { + home.packages = with pkgs; [ nixvim neovide ]; + programs.neovim.enable = false; + home.file.".config/neovide/config.toml" = { + source = tomlFormat.generate "neovide-config" neovideConfig; + }; + }; +} diff --git a/modules/home-manager/vscode.nix b/modules/home-manager/vscode.nix new file mode 100644 index 0000000..9017f4c --- /dev/null +++ b/modules/home-manager/vscode.nix @@ -0,0 +1,190 @@ +{ inputs, config, lib, pkgs, ... }: +with lib; + +let + cfg = config.custom-hm.vscode; + + packages = { + nixPackages = { + systemPackages = with pkgs; [ nixd nixpkgs-fmt ]; + extension = with inputs.nix-vscode-extensions.extensions.${pkgs.system}.vscode-marketplace; [ + jnoortheen.nix-ide + ]; + settings = { + "nix.enableLanguageServer" = true; + "nix.formatterPath" = "nixpkgs-fmt"; + "nix.serverPath" = "nixd"; + }; + }; + cxxPackages = { + systemPackages = with pkgs; [ clang-tools cmake-format ]; + extension = with inputs.nix-vscode-extensions.extensions.${pkgs.system}.vscode-marketplace; [ + llvm-vs-code-extensions.vscode-clangd + (ms-vscode.cmake-tools.overrideAttrs (_: { sourceRoot = "extension"; })) + twxs.cmake + ms-vscode.cpptools + ]; + settings = { + "cmake.configureOnEdit" = false; + "cmake.showOptionsMovedNotification" = false; + "cmake.showNotAllDocumentsSavedQuestion" = false; + "cmake.pinnedCommands" = [ + "workbench.action.tasks.configureTaskRunner" + "workbench.action.tasks.runTask" + ]; + "C_Cpp.intelliSenseEngine" = "Disabled"; + }; + }; + pythonPackages = { + systemPackages = with pkgs; [ ]; + extension = with inputs.nix-vscode-extensions.extensions.${pkgs.system}.vscode-marketplace; [ + ms-python.python + ]; + settings = { }; + }; + scalaPackages = { + systemPackages = with pkgs; [ coursier metals ]; + extension = with inputs.nix-vscode-extensions.extensions.${pkgs.system}.vscode-marketplace; [ + scala-lang.scala + scalameta.metals + ]; + settings = { }; + }; + latexPackages = { + systemPackages = with pkgs; [ texliveSmall ]; + extension = with inputs.nix-vscode-extensions.extensions.${pkgs.system}.vscode-marketplace; [ + james-yu.latex-workshop + ]; + settings = { + "latex-workshop.latex.autoBuild.run" = "never"; + "latex-workshop.latex.tools" = [ + { + "name" = "xelatex"; + "command" = "xelatex"; + "args" = [ "-synctex=1" "-interaction=nonstopmode" "-file-line-error" "%DOCFILE%" ]; + } + { + "name" = "pdflatex"; + "command" = "pdflatex"; + "args" = [ "-synctex=1" "-interaction=nonstopmode" "-file-line-error" "%DOCFILE%" ]; + } + { "name" = "bibtex"; "command" = "bibtex"; "args" = [ "%DOCFILE%" ]; } + ]; + "latex-workshop.latex.recipes" = [ + { "name" = "xelatex"; "tools" = [ "xelatex" ]; } + { "name" = "pdflatex"; "tools" = [ "pdflatex" ]; } + { "name" = "xe->bib->xe->xe"; "tools" = [ "xelatex" "bibtex" "xelatex" "xelatex" ]; } + { "name" = "pdf->bib->pdf->pdf"; "tools" = [ "pdflatex" "bibtex" "pdflatex" "pdflatex" ]; } + ]; + "[latex]" = { + "editor.formatOnPaste" = false; + "editor.suggestSelection" = "recentlyusedbyprefix"; + "editor.wordWrap" = "bounded"; + "editor.wordWrapColumn" = 80; + "editor.unicodeHighlight.ambiguousCharacters" = false; + }; + }; + }; + }; + llmExtensions = [ pkgs.vscode-extensions.continue.continue ]; + + languages = [ "nix" "cxx" "python" "scala" "latex" ]; + zipAttrsWithLanguageOption = (attr: + (map (l: (lib.mkIf cfg.languages.${l} packages."${l}Packages".${attr})) languages) + ); +in +{ + options.custom-hm.vscode = { + enable = mkEnableOption "Vscode config"; + languages = { + nix = mkOption { + type = lib.types.bool; + default = true; + }; + cxx = mkEnableOption "C++"; + python = mkEnableOption "Python"; + scala = mkEnableOption "Scala"; + latex = mkEnableOption "Latex"; + }; + llm = mkEnableOption "tab completion with Continue and ollama"; + }; + config = mkIf cfg.enable { + nixpkgs.config.allowUnfree = true; + + home.packages = lib.mkMerge ([ + [ pkgs.clang-tools ] + (mkIf cfg.llm [ pkgs.ollama ]) + ] ++ zipAttrsWithLanguageOption "systemPackages"); + programs.vscode = { + enable = true; + package = pkgs.vscode.override { commandLineArgs = "--enable-wayland-ime"; }; + enableUpdateCheck = false; + enableExtensionUpdateCheck = false; + mutableExtensionsDir = false; + extensions = lib.mkMerge ([ + (with inputs.nix-vscode-extensions.extensions.${pkgs.system}.vscode-marketplace; [ + mkhl.direnv + + ms-azuretools.vscode-docker + ms-vscode-remote.remote-ssh + vscodevim.vim + github.vscode-pull-request-github + gruntfuggly.todo-tree # todo highlight + + # Markdown + davidanson.vscode-markdownlint + # Latex + # Scale / chisel + sterben.fpga-support + + ms-vscode-remote.remote-ssh-edit + mushan.vscode-paste-image + ]) + + (with pkgs.vscode-extensions; [ + waderyan.gitblame + catppuccin.catppuccin-vsc + # Rust + rust-lang.rust-analyzer + ]) + + (mkIf cfg.llm llmExtensions) + ] ++ zipAttrsWithLanguageOption "extension"); + userSettings = lib.mkMerge ([ + { + "workbench.colorTheme" = "Catppuccin Macchiato"; + "terminal.integrated.sendKeybindingsToShell" = true; + "extensions.ignoreRecommendations" = true; + "files.autoSave" = "afterDelay"; + "editor.inlineSuggest.enabled" = true; + "editor.rulers" = [ + 80 + ]; + "editor.mouseWheelZoom" = true; + "git.autofetch" = false; + "window.zoomLevel" = -1; + + "extensions.experimental.affinity" = { + "vscodevim.vim" = 1; + }; + } + ] ++ zipAttrsWithLanguageOption "settings"); + }; + + home.file.".continue/config.json".text = lib.generators.toJSON { } { + models = [ + { + model = "AUTODETECT"; + provider = "ollama"; + title = "Ollama"; + } + ]; + tabAutocompleteModel = { + model ="deepseek-coder:6.7b-base"; + provider = "ollama"; + title = "codegemma"; + }; + }; + }; + +} diff --git a/modules/home-manager/zellij.nix b/modules/home-manager/zellij.nix new file mode 100644 index 0000000..e03047c --- /dev/null +++ b/modules/home-manager/zellij.nix @@ -0,0 +1,33 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.custom-hm.zellij; +in +{ + options.custom-hm.zellij = { + enable = mkEnableOption "zellij configurations"; + }; + config = { + programs.zellij = mkIf cfg.enable { + enable = true; + settings = { + default_shell = "fish"; + keybinds = { + unbind = [ + "Ctrl p" + "Ctrl n" + ]; + shared_except = { + _args = [ "pane" "locked" ]; + bind = { + _args = [ "Ctrl b"]; + SwitchToMode = "Pane"; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/nixos/common-settings/auth.nix b/modules/nixos/common-settings/auth.nix new file mode 100644 index 0000000..f70d350 --- /dev/null +++ b/modules/nixos/common-settings/auth.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) mkIf mkEnableOption mkOption types; + + cfg = config.commonSettings.auth; +in +{ + options.commonSettings.auth = { + enable = mkEnableOption "Common auth settings for servers"; + }; + + config = mkIf cfg.enable { + custom.kanidm-client = { + enable = true; + uri = "https://auth.xinyang.life"; + asSSHAuth = { + enable = true; + allowedGroups = [ "linux_users" ]; + }; + sudoers = [ "xin@auth.xinyang.life" ]; + }; + + services.openssh = { + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "no"; + GSSAPIAuthentication = "no"; + KerberosAuthentication = "no"; + }; + }; + services.fail2ban.enable = true; + + security.sudo = { + execWheelOnly = true; + wheelNeedsPassword = false; + }; + }; +} + diff --git a/modules/nixos/common-settings/nix-conf.nix b/modules/nixos/common-settings/nix-conf.nix new file mode 100644 index 0000000..5313b9f --- /dev/null +++ b/modules/nixos/common-settings/nix-conf.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) mkIf mkEnableOption mkOption types; + + cfg = config.commonSettings.nix; +in +{ + options.commonSettings.nix = { + enable = mkOption { + default = true; + type = types.bool; + }; + enableMirrors = mkEnableOption "cache.nixos.org mirrors in Mainland China"; + signing = { + enable = mkEnableOption "Sign locally-built paths"; + keyFile = mkOption { + default = "/etc/nix/key.private"; + type = types.str; + }; + }; + }; + + config = mkIf cfg.enable { + nix.package = pkgs.nixVersions.latest; + + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + + nix.optimise.automatic = true; + + nix.settings = { + experimental-features = [ "nix-command" "flakes" ]; + auto-optimise-store = true; + trusted-users = [ "root" ]; + + substituters = [ + "https://nix-community.cachix.org" + "https://cache.garnix.io" + ]; + + extra-substituters = mkIf cfg.enableMirrors [ + "https://mirrors.cernet.edu.cn/nix-channels/store?priority=20" + ]; + + trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g=" + "xin-1:8/ul1IhdWLswERF/8RfeAw8VZqjwHrJ1x55y1yjxQ+Y=" + ]; + + secret-key-files = mkIf cfg.signing.enable [ + cfg.signing.keyFile + ]; + }; + }; +} + diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix new file mode 100644 index 0000000..3fe5855 --- /dev/null +++ b/modules/nixos/default.nix @@ -0,0 +1,17 @@ +{ config, pkgs, ... }: +{ + imports = [ + ./common-settings/auth.nix + ./common-settings/nix-conf.nix + ./restic.nix + ./vaultwarden.nix + ./prometheus + ./hedgedoc.nix + ./sing-box.nix + ./kanidm-client.nix + ./ssh-tpm-agent.nix # FIXME: Waiting for upstream merge + ./forgejo-actions-runner.nix + ./oidc-agent.nix + ./miniflux.nix + ]; +} diff --git a/modules/nixos/forgejo-actions-runner.nix b/modules/nixos/forgejo-actions-runner.nix new file mode 100644 index 0000000..5b76c69 --- /dev/null +++ b/modules/nixos/forgejo-actions-runner.nix @@ -0,0 +1,34 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.custom.forgejo-actions-runner; +in +{ + options = { + custom.forgejo-actions-runner = { + enable = lib.mkEnableOption "TPM supported ssh agent in go"; + tokenFile = lib.mkOption { + type = lib.types.path; + }; + }; + }; + config = lib.mkIf cfg.enable { + virtualisation.docker.enable = true; + services.gitea-actions-runner.package = pkgs.forgejo-actions-runner; + services.gitea-actions-runner.instances = { + "git.xinyang.life" = { + enable = true; + url = "https://git.xinyang.life"; + tokenFile = cfg.tokenFile; + name = config.networking.hostName; + labels = [ + "debian-latest:docker://node:18-bullseye" + "ubuntu-latest:docker://node:18-bullseye" + "nix:docker://xiny/nix-runner:2.21.0-pkgs-23.11" + ]; + settings = { + container.network = "host"; + }; + }; + }; + }; +} diff --git a/modules/nixos/hedgedoc.nix b/modules/nixos/hedgedoc.nix new file mode 100644 index 0000000..6aa5de2 --- /dev/null +++ b/modules/nixos/hedgedoc.nix @@ -0,0 +1,83 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.custom.hedgedoc; +in +{ + options = { + custom.hedgedoc = { + enable = mkEnableOption "HedgeDoc Markdown Editor"; + domain = mkOption { + type = types.str; + default = "docs.example.com"; + description = "Domain name of the HedgeDoc server"; + }; + caddy = mkOption { + type = types.bool; + default = true; + description = "Enable Caddy as reverse proxy"; + }; + mediaPath = mkOption { + type = types.path; + default = /var/lib/hedgedoc/uploads; + description = "Directory for storing medias"; + }; + oidc = { + enable = mkEnableOption "OIDC support for HedgeDoc"; + baseURL = mkOption { + type = types.str; + }; + authorizationURL = mkOption { + type = types.str; + }; + tokenURL = mkOption { + type = types.str; + }; + userProfileURL = mkOption { + type = types.str; + }; + }; + environmentFile = mkOption { + type = types.path; + }; + }; + }; + config = mkIf cfg.enable { + services.hedgedoc = { + enable = true; + environmentFile = cfg.environmentFile; + settings = { + domain = cfg.domain; + protocolUseSSL = cfg.caddy; + uploadsPath = cfg.mediaPath; + path = "/run/hedgedoc/hedgedoc.sock"; + email = false; + allowEmailRegister = false; + oauth2 = mkIf cfg.oidc.enable { + baseURL = cfg.oidc.baseURL; + authorizationURL = cfg.oidc.authorizationURL; + tokenURL = cfg.oidc.tokenURL; + userProfileURL = cfg.oidc.userProfileURL; + userProfileEmailAttr = "email"; + userProfileUsernameAttr = "name"; + userProfileDisplayNameAttr = "preferred_name"; + scope = "openid email profile"; + clientID = "$HEDGEDOC_CLIENT_ID"; + clientSecret = "$HEDGEDOC_CLIENT_SECRET"; + }; + allowAnonymous = false; + defaultPermission = "private"; + }; + }; + services.caddy = mkIf cfg.caddy { + enable = true; + virtualHosts."https://${cfg.domain}".extraConfig = '' + reverse_proxy unix/${config.services.hedgedoc.settings.path} + ''; + }; + users.users.caddy.extraGroups = mkIf cfg.caddy [ "hedgedoc" ]; + + }; +} diff --git a/modules/nixos/inbounds.nix b/modules/nixos/inbounds.nix new file mode 100644 index 0000000..0cbd33f --- /dev/null +++ b/modules/nixos/inbounds.nix @@ -0,0 +1,126 @@ +{ config +, lib +, ... }: +let + cfg = config.custom.sing-box-server; + + secretFileType = lib.types.submodule { + _secret = lib.types.path; + }; + singTls = { + enabled = true; + server_name = config.deployment.targetHost; + key_path = config.security.acme.certs.${config.deployment.targetHost}.directory + "/key.pem"; + certificate_path = config.security.acme.certs.${config.deployment.targetHost}.directory + "/cert.pem"; + }; +in +{ + options = { + enable = lib.mkEnableOption "sing-box proxy server"; + users = lib.types.listOf lib.types.submodule { + name = lib.mkOption { + type = lib.types.str; + default = "proxy"; + }; + password = lib.mkOption { + type = secretFileType; + }; + uuid = lib.mkOption { + type = secretFileType; + }; + }; + wgOut = { + privKeyFile = lib.mkOption { + type = lib.types.path; + }; + pubkey = lib.mkOption { + type = lib.types.str; + default = "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="; + }; + }; + inbounds = { + trojan = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + }; + }; + tuic = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + }; + ports = lib.mkOption { + type = lib.types.listOf lib.types.int; + default = lib.range 6311 6313; + }; + directPorts = lib.mkOption { + type = lib.types.listOf lib.types.int; + default = [ 6314 ]; + }; + }; + }; + }; + config = lib.mkIf cfg.enable { + services.sing-box = { + enable = true; + settings = { + dns = { + servers = [ + { + address = "1.1.1.1"; + detour = "wg-out"; + } + ]; + }; + inbounds = [ + # TODO: Trojan and tuic enable + { + tag = "trojan-in"; + type = "trojan"; + listen = "::"; + listen_port = 8080; + users = map (u: removeAttrs u [ "uuid" ]) cfg.users; + tls = singTls; + } + ] ++ lib.forEach (cfg.tuic.ports ++ cfg.tuic.directPorts) (port: { + tag = "tuic-in" + toString port; + type = "tuic"; + listen = "::"; + listen_port = port; + congestion_control = "bbr"; + users = cfg.users; + tls = singTls; + }); + outbounds = [ + { + type = "wireguard"; + tag = "wg-out"; + private_key = cfg.wgOut.privKeyFile; + local_address = [ + "172.16.0.2/32" + "2606:4700:110:82ed:a443:3c62:6cbc:b59b/128" + ]; + peers = [ + { public_key= cfg.wgOut.pubkey; + allowed_ips = [ "0.0.0.0/0" "::/0" ]; + server = "162.159.192.1"; + server_port = 500; + } + ]; + } + { type = "direct"; tag = "direct-out"; } + { type = "dns"; tag = "dns-out"; } + ]; + route = { + rules = [ + { outbound = "dns-out"; protocol = "dns"; } + ] ++ lib.forEach cfg.tuic.directPorts (port: { + inbound = "tuic-in" + toString port; + outbound = "direct-out"; + }); + }; + }; + }; + }; +} \ No newline at end of file diff --git a/modules/nixos/kanidm-client.nix b/modules/nixos/kanidm-client.nix new file mode 100644 index 0000000..41d974d --- /dev/null +++ b/modules/nixos/kanidm-client.nix @@ -0,0 +1,77 @@ +{ config, pkgs, lib, ... }: +with lib; + +let + cfg = config.custom.kanidm-client; +in +{ + options = { + custom.kanidm-client = { + enable = mkEnableOption "Kanidm client service"; + asSSHAuth = mkOption { + type = types.submodule { + options = { + enable = mkEnableOption "Kanidm as system authentication source"; + allowedGroups = mkOption { + type = types.listOf types.str; + example = [ "linux_users" ]; + }; + hardening = mkOption { + type = types.bool; + default = false; + }; + }; + }; + }; + sudoers = mkOption { + type = types.listOf types.str; + default = [ ]; + }; + uri = mkOption { + type = types.str; + }; + }; + }; + config = mkIf cfg.enable { + services.kanidm = mkMerge + [ (mkIf cfg.enable { + enableClient = true; + clientSettings = { + uri = cfg.uri; + }; + }) + (mkIf cfg.asSSHAuth.enable { + enablePam = true; + unixSettings = { + pam_allowed_login_groups = cfg.asSSHAuth.allowedGroups; + default_shell = "/bin/sh"; + }; + }) + ]; + services.openssh = mkIf cfg.asSSHAuth.enable { + enable = true; + authorizedKeysCommand = "/etc/ssh/auth %u"; + authorizedKeysCommandUser = "kanidm-ssh-runner"; + settings = mkIf cfg.asSSHAuth.enable { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = lib.mkForce "no"; + GSSAPIAuthentication = "no"; + KerberosAuthentication = "no"; + }; + }; + + environment.etc."ssh/auth" = mkIf cfg.asSSHAuth.enable { + mode = "0555"; + text = '' + #!${pkgs.stdenv.shell} + ${pkgs.kanidm}/bin/kanidm_ssh_authorizedkeys $1 + ''; + }; + users.groups.wheel.members = cfg.sudoers; + users.groups.kanidm-ssh-runner = { }; + users.users.kanidm-ssh-runner = { isSystemUser = true; group = "kanidm-ssh-runner"; }; + + }; +} + diff --git a/modules/nixos/miniflux.nix b/modules/nixos/miniflux.nix new file mode 100644 index 0000000..2d539e0 --- /dev/null +++ b/modules/nixos/miniflux.nix @@ -0,0 +1,133 @@ +{ config, pkgs, lib, ... }: +let + inherit (lib) mkEnableOption mkPackageOption mkOption types literalExpression mkIf mkDefault; + cfg = config.custom.miniflux; + + defaultAddress = "localhost:8080"; + + pgbin = "${config.services.postgresql.package}/bin"; + preStart = pkgs.writeScript "miniflux-pre-start" '' + #!${pkgs.runtimeShell} + ${pgbin}/psql "miniflux" -c "CREATE EXTENSION IF NOT EXISTS hstore" + ''; +in +{ + options = { + custom.miniflux = { + enable = mkEnableOption "miniflux"; + + package = mkPackageOption pkgs "miniflux" { }; + + oauth2SecretFile = mkOption { + type = types.path; + }; + + environment = mkOption { + type = with types; attrsOf (oneOf [ int str ]); + }; + + createDatabaseLocally = mkOption { + type = types.bool; + default = true; + description = '' + Whether a PostgreSQL database should be automatically created and + configured on the local host. If set to `false`, you need provision a + database yourself and make sure to create the hstore extension in it. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + services.miniflux.enable = false; + custom.miniflux.environment = { + LISTEN_ADDR = mkDefault defaultAddress; + RUN_MIGRATIONS = mkDefault 1; + DATABASE_URL = lib.mkIf cfg.createDatabaseLocally "user=miniflux host=/run/postgresql dbname=miniflux"; + OAUTH2_CLIENT_SECRET_FILE = "%d/oauth2_secret"; + WATCHDOG = mkDefault 1; + }; + + services.postgresql = lib.mkIf cfg.createDatabaseLocally { + enable = true; + ensureUsers = [{ + name = "miniflux"; + ensureDBOwnership = true; + }]; + ensureDatabases = [ "miniflux" ]; + }; + + systemd.services.miniflux-dbsetup = lib.mkIf cfg.createDatabaseLocally { + description = "Miniflux database setup"; + requires = [ "postgresql.service" ]; + after = [ "network.target" "postgresql.service" ]; + serviceConfig = { + Type = "oneshot"; + User = config.services.postgresql.superUser; + ExecStart = preStart; + }; + }; + + systemd.services.miniflux = { + description = "Miniflux service"; + wantedBy = [ "multi-user.target" ]; + requires = lib.optional cfg.createDatabaseLocally "miniflux-dbsetup.service"; + after = [ "network.target" ] + ++ lib.optionals cfg.createDatabaseLocally [ "postgresql.service" "miniflux-dbsetup.service" ]; + + serviceConfig = { + Type = "notify"; + ExecStart = lib.getExe cfg.package; + User = "miniflux"; + DynamicUser = true; + LoadCredential = [ "oauth2_secret:${cfg.oauth2SecretFile}" ]; + RuntimeDirectory = "miniflux"; + RuntimeDirectoryMode = "0750"; + WatchdogSec = 60; + WatchdogSignal = "SIGKILL"; + Restart = "always"; + RestartSec = 5; + + # Hardening + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" ]; + UMask = "0077"; + }; + + environment = lib.mapAttrs (_: toString) cfg.environment; + }; + environment.systemPackages = [ cfg.package ]; + + security.apparmor.policies."bin.miniflux".profile = '' + include + ${cfg.package}/bin/miniflux { + include + include + include + include "${pkgs.apparmorRulesFromClosure { name = "miniflux"; } cfg.package}" + r ${cfg.package}/bin/miniflux, + r @{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size, + rw /run/miniflux/**, + } + ''; + }; +} diff --git a/modules/nixos/oidc-agent.nix b/modules/nixos/oidc-agent.nix new file mode 100644 index 0000000..35ce679 --- /dev/null +++ b/modules/nixos/oidc-agent.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) mkIf mkEnableOption mkOption types; + + cfg = config.programs.oidc-agent; + providerFormat = pkgs.formats.json {}; +in +{ + options.programs.oidc-agent = { + enable = mkEnableOption "OpenID Connect Agent"; + package = mkOption { + type = types.package; + default = pkgs.oidc-agent; + description = '' + Which oidc-agent package to use + ''; + }; + providers = mkOption { + type = providerFormat.type; + default = {}; + description = '' + Configuration of providers which contains a json array of json objects + each describing an issuer, see https://indigo-dc.gitbook.io/oidc-agent/configuration/issuers + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.oidc-agent = { + unitConfig = { + Description = "OpenID Connect Agent"; + Documentation = "man:oidc-agent(1)"; + }; + serviceConfig = { + ExecStart = "${cfg.package}/bin/oidc-agent -d --log-stderr -a %t/oidc-agent"; + }; + }; + + # environment.etc."oidc-agent/config".source = "${pkgs.oidc-agent}/etc/oidc-agent/config"; + + # environment.etc."oidc-agent/issuer.config.d".source = + # "${pkgs.oidc-agent}/etc/oidc-agent/issuer.config.d"; + + # environment.etc."oidc-agent/issuer.config".source = + # providerFormat.generate "oidc-agent-issuer.config" cfg.providers; + + environment.extraInit = ''export OIDC_SOCK="$XDG_RUNTIME_DIR/oidc-agent"''; + }; +} diff --git a/modules/nixos/prometheus/blackbox.nix b/modules/nixos/prometheus/blackbox.nix new file mode 100644 index 0000000..7886b06 --- /dev/null +++ b/modules/nixos/prometheus/blackbox.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.custom.prometheus; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.blackbox.enable) { + services.prometheus.exporters.blackbox = { + enable = true; + listenAddress = "127.0.0.1"; + configFile = pkgs.writeText "blackbox.config.yaml" ( + lib.generators.toYAML {} { + modules = { + tcp4_connect = { + prober = "tcp"; + tcp = { + ip_protocol_fallback = false; + preferred_ip_protocol = "ip4"; + tls = false; + }; + timeout = "15s"; + }; + }; + } + ); + }; + + services.prometheus.scrapeConfigs = [ + { + job_name = "blackbox"; + scrape_interval = "1m"; + metrics_path = "/probe"; + params = { + module = [ "tcp4_connect" ]; + }; + static_configs = [ + { + targets = [ + "tok-00.namely.icu:8080" + "la-00.video.namely.icu:8080" + "auth.xinyang.life:443" + "home.xinyang.life:8000" + ]; + } + ]; + relabel_configs = [ + { + source_labels = [ "__address__" ]; + target_label = "__param_target"; + } + { + source_labels = [ "__param_target" ]; + target_label = "instance"; + } + { + target_label = "__address__"; + replacement = "127.0.0.1:${toString config.services.prometheus.exporters.blackbox.port}"; + } + ]; + } + { + job_name = "blackbox_exporter"; + static_configs = [ + { targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.blackbox.port}" ]; } + ]; + } + ]; + + custom.prometheus.ruleModules = [ + { + name = "probe_alerts"; + rules = [ + { + alert = "HighProbeLatency"; + expr = "probe_duration_seconds > 0.5"; + for = "2m"; + labels = { severity = "warning"; }; + annotations = { summary = "High request latency on {{ $labels.instance }}"; description = "95th percentile of request latency is above 0.5 seconds for the last 2 minutes."; }; + } + ]; + } + ]; + }; +} diff --git a/modules/nixos/prometheus/caddy.nix b/modules/nixos/prometheus/caddy.nix new file mode 100644 index 0000000..96b7f43 --- /dev/null +++ b/modules/nixos/prometheus/caddy.nix @@ -0,0 +1,38 @@ +{ config, lib, ... }: +let + cfg = config.custom.prometheus; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.caddy.enable) { + services.caddy.globalConfig = lib.mkIf cfg.exporters.caddy.enable '' + servers { + metrics + } + ''; + + services.prometheus.scrapeConfigs = [ + { + job_name = "caddy"; + static_configs = [ + { targets = [ "127.0.0.1:2019" ]; } + ]; + } + ]; + + custom.prometheus.ruleModules = [ + { + name = "caddy_alerts"; + rules = [ + { + alert = "UpstreamHealthy"; + expr = "caddy_reverse_proxy_upstreams_healthy != 1"; + for = "5m"; + labels = { severity = "critical"; }; + annotations = { summary = "Upstream {{ $labels.unstream }} not healthy"; }; + } + ]; + } + ]; + }; + +} diff --git a/modules/nixos/prometheus/default.nix b/modules/nixos/prometheus/default.nix new file mode 100644 index 0000000..a560737 --- /dev/null +++ b/modules/nixos/prometheus/default.nix @@ -0,0 +1,206 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.custom.prometheus; + mkExporterOption = enableOption: (mkOption { + type = types.bool; + default = enableOption; + description = "Enable this exporter"; + }); + + mkRulesOption = mkOption { + type = types.listOf (types.submodule { + options = { + name = mkOption { + type = lib.types.str; + }; + rules = mkOption { + type = lib.types.listOf lib.types.attrs; + }; + }; + }); + }; +in +{ + imports = [ + ./blackbox.nix + ./caddy.nix + ./gotosocial.nix + ./immich.nix + ./miniflux.nix + ./ntfy-sh.nix + ./restic.nix + ]; + + options = { + custom.prometheus = { + enable = mkEnableOption "Prometheus instance"; + exporters = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable Prometheus exporter on every supported services"; + }; + + restic.enable = mkExporterOption config.services.restic.server.enable; + blackbox.enable = mkExporterOption false; + caddy.enable = mkExporterOption config.services.caddy.enable; + gotosocial.enable = mkExporterOption config.services.gotosocial.enable; + immich.enable = mkExporterOption config.services.immich.enable; + miniflux.enable = mkExporterOption config.services.miniflux.enable; + ntfy-sh.enable = mkExporterOption config.services.ntfy-sh.enable; + }; + grafana = { + enable = mkEnableOption "Grafana Cloud"; + password_file = mkOption { + type = types.path; + }; + }; + ruleModules = mkRulesOption; + }; + }; + + config = mkIf cfg.enable + { + services.tailscale = { + enable = true; + permitCertUid = config.services.caddy.user; + openFirewall = true; + }; + + services.caddy = { + enable = true; + virtualHosts."${config.networking.hostName}.coho-tet.ts.net".extraConfig = '' + reverse_proxy 127.0.0.1:${toString config.services.prometheus.port} + ''; + }; + + services.prometheus = mkIf cfg.enable + { + enable = true; + port = 9091; + globalConfig.external_labels = { hostname = config.networking.hostName; }; + remoteWrite = mkIf cfg.grafana.enable [ + { + name = "grafana"; + url = "https://prometheus-prod-24-prod-eu-west-2.grafana.net/api/prom/push"; + basic_auth = { + username = "1340065"; + password_file = cfg.grafana.password_file; + }; + } + ]; + exporters = { + node = { + enable = true; + enabledCollectors = [ + "loadavg" + "time" + "systemd" + ]; + listenAddress = "127.0.0.1"; + port = 9100; + }; + }; + scrapeConfigs = [ + { + job_name = "prometheus"; + static_configs = [ + { targets = [ "localhost:${toString config.services.prometheus.port}" ]; } + ]; + } + { + job_name = "node"; + static_configs = [ + { targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ]; } + ]; + } + ]; + + alertmanager = { + enable = true; + listenAddress = "127.0.0.1"; + logLevel = "debug"; + configuration = { + route = { + receiver = "ntfy"; + }; + receivers = [ + { + name = "ntfy"; + webhook_configs = [ + { + url = "https://ntfy.xinyang.life/prometheus-alerts?tpl=yes&m=${lib.escapeURL '' + Alert {{.status}} + {{range .alerts}}-----{{range $k,$v := .labels}} + {{$k}}={{$v}}{{end}} + {{end}} + ''}"; + send_resolved = true; + } + ]; + } + ]; + }; + }; + + alertmanagers = [ + { + scheme = "http"; + static_configs = [ + { + targets = [ + "${config.services.prometheus.alertmanager.listenAddress}:${toString config.services.prometheus.alertmanager.port}" + ]; + } + ]; + } + ]; + rules = [ (lib.generators.toYAML { } { groups = cfg.ruleModules; }) ]; + }; + custom.prometheus.ruleModules = [ + { + name = "system_alerts"; + rules = [ + { + alert = "SystemdFailedUnits"; + expr = "node_systemd_unit_state{state=\"failed\"} > 0"; + for = "5m"; + labels = { severity = "critical"; }; + annotations = { summary = "Systemd has failed units on {{ $labels.instance }}"; description = "There are {{ $value }} failed units on {{ $labels.instance }}. Immediate attention required!"; }; + } + { + alert = "HighLoadAverage"; + expr = "node_load1 > 0.8 * count without (cpu) (node_cpu_seconds_total{mode=\"idle\"})"; + for = "1m"; + labels = { severity = "warning"; }; + annotations = { summary = "High load average detected on {{ $labels.instance }}"; description = "The 1-minute load average ({{ $value }}) exceeds 80% the number of CPUs."; }; + } + { + alert = "HighTransmitTraffic"; + expr = "rate(node_network_transmit_bytes_total{device!=\"lo\"}[5m]) > 100000000"; + for = "1m"; + labels = { severity = "warning"; }; + annotations = { summary = "High network transmit traffic on {{ $labels.instance }} ({{ $labels.device }})"; description = "The network interface {{ $labels.device }} on {{ $labels.instance }} is transmitting data at a rate exceeding 100 MB/s for the last 1 minute."; }; + } + { + alert = "NetworkTrafficExceedLimit"; + expr = ''increase(node_network_transmit_bytes_total{device!="lo",device!~"tailscale.*",device!~"wg.*",device!~"br.*"}[30d]) > 322122547200''; + for = "0m"; + labels = { severity = "critical"; }; + annotations = { summary = "Outbound network traffic exceed 300GB for last 30 day"; }; + } + { + alert = "JobDown"; + expr = "up == 0"; + for = "1m"; + labels = { severity = "critical"; }; + annotations = { summary = "Job {{ $labels.job }} down for 1m."; }; + } + ]; + } + ]; + }; +} diff --git a/modules/nixos/prometheus/gotosocial.nix b/modules/nixos/prometheus/gotosocial.nix new file mode 100644 index 0000000..a643d19 --- /dev/null +++ b/modules/nixos/prometheus/gotosocial.nix @@ -0,0 +1,19 @@ +{ config, lib, ... }: +let + cfg = config.custom.prometheus; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.gotosocial.enable) { + services.gotosocial.settings = { + metrics-enabled = true; + }; + services.prometheus.scrapeConfigs = [ + { + job_name = "gotosocial"; + static_configs = [ + { targets = [ "localhost:8080" ]; } + ]; + } + ]; + }; +} diff --git a/modules/nixos/prometheus/immich.nix b/modules/nixos/prometheus/immich.nix new file mode 100644 index 0000000..095075d --- /dev/null +++ b/modules/nixos/prometheus/immich.nix @@ -0,0 +1,26 @@ +{ config, lib, ... }: +let + cfg = config.custom.prometheus; + immichEnv = config.services.immich.environment; + metricPort = + if builtins.hasAttr "IMMICH_API_METRICS_PORT" immichEnv + then immichEnv.IMMICH_API_METRICS_PORT + else 8081; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.immich.enable) { + services.immich.environment = { + IMMICH_METRICS = "true"; + }; + + services.prometheus.scrapeConfigs = [ + { + job_name = "immich"; + static_configs = [ + { targets = [ "127.0.0.1:${toString metricPort}" ]; } + ]; + } + ]; + }; + +} diff --git a/modules/nixos/prometheus/miniflux.nix b/modules/nixos/prometheus/miniflux.nix new file mode 100644 index 0000000..5339de3 --- /dev/null +++ b/modules/nixos/prometheus/miniflux.nix @@ -0,0 +1,17 @@ +{ config, lib, ... }: +let + cfg = config.custom.prometheus; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.miniflux.enable) { + systemd.services.miniflux.environment.METRICS_COLLECTOR = "1"; + services.prometheus.scrapeConfigs = [ + { + job_name = "miniflux"; + static_configs = [ + { targets = [ config.systemd.services.miniflux.environment.LISTEN_ADDR ]; } + ]; + } + ]; + }; +} diff --git a/modules/nixos/prometheus/ntfy-sh.nix b/modules/nixos/prometheus/ntfy-sh.nix new file mode 100644 index 0000000..513f130 --- /dev/null +++ b/modules/nixos/prometheus/ntfy-sh.nix @@ -0,0 +1,17 @@ +{ config, lib, ... }: +let + cfg = config.custom.prometheus; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.ntfy-sh.enable) { + services.ntfy-sh.settings.enable-metrics = true; + services.prometheus.scrapeConfigs = [ + { + job_name = "ntfy-sh"; + static_configs = [ + { targets = [ "ntfy.xinyang.life" ]; } + ]; + } + ]; + }; +} diff --git a/modules/nixos/prometheus/restic.nix b/modules/nixos/prometheus/restic.nix new file mode 100644 index 0000000..750b61a --- /dev/null +++ b/modules/nixos/prometheus/restic.nix @@ -0,0 +1,41 @@ +{ config, lib, ... }: +let + cfg = config.custom.prometheus; +in +{ + config = lib.mkIf (cfg.enable && cfg.exporters.restic.enable) { + services.restic.server.prometheus = true; + + services.prometheus.scrapeConfigs = [ + (lib.mkIf cfg.exporters.restic.enable { + job_name = "restic"; + static_configs = [ + { targets = [ config.services.restic.server.listenAddress ]; } + ]; + }) + ]; + + custom.prometheus.ruleModules = [ + { + name = "restic_alerts"; + rules = [ + { + alert = "ResticCheckFailed"; + expr = "restic_check_success == 0"; + for = "5m"; + labels = { severity = "critical"; }; + annotations = { summary = "Restic check failed (instance {{ $labels.instance }})"; description = "Restic check failed\\n VALUE = {{ $value }}\\n LABELS = {{ $labels }}"; }; + } + { + alert = "ResticOutdatedBackup"; + expr = "time() - restic_backup_timestamp > 518400"; + for = "0m"; + labels = { severity = "critical"; }; + annotations = { summary = "Restic {{ $labels.client_hostname }} / {{ $labels.client_username }} backup is outdated"; description = "Restic backup is outdated\\n VALUE = {{ $value }}\\n LABELS = {{ $labels }}"; }; + } + ]; + } + ]; + }; + +} diff --git a/modules/nixos/restic.nix b/modules/nixos/restic.nix new file mode 100644 index 0000000..07a8dad --- /dev/null +++ b/modules/nixos/restic.nix @@ -0,0 +1,48 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.custom.restic; +in +{ + options = { + custom.restic = { + enable = lib.mkEnableOption "restic"; + repositoryFile = lib.mkOption { + type = lib.types.str; + default = ""; + }; + passwordFile = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + }; + config = lib.mkIf cfg.enable { + services.restic.backups = { + remotebackup = { + repositoryFile = cfg.repositoryFile; + passwordFile = cfg.passwordFile; + paths = [ + "/home" + "/var/lib" + ]; + exclude = [ + "/home/*/.cache" + "/home/*/.cargo" + "/home/*/.local/share/Steam" + "/home/*/.local/share/flatpak" + ]; + timerConfig = { + OnCalendar = "00:05"; + RandomizedDelaySec = "5h"; + }; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 75" + ]; + }; + }; + }; +} + diff --git a/modules/nixos/sing-box.nix b/modules/nixos/sing-box.nix new file mode 100644 index 0000000..572291b --- /dev/null +++ b/modules/nixos/sing-box.nix @@ -0,0 +1,84 @@ +{ config, pkgs, lib, utils, ... }: +let + cfg = config.custom.sing-box; + settingsFormat = pkgs.formats.json { }; +in +{ + options = { + custom.sing-box = { + enable = lib.mkEnableOption "sing-box"; + + package = lib.mkPackageOption pkgs "sing-box" { }; + + stateDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/sing-box"; + }; + + configFile = { + urlFile = lib.mkOption { + type = lib.types.path; + }; + name = lib.mkOption { + type = lib.types.str; + default = "config.json"; + }; + hash = lib.mkOption { + type = lib.types.str; + example = "9a304bcb87d4c3f1e50f6281f25dd78635255ebde06cd4d2555729ecda43aed4"; + }; + }; + + overrideSettings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + route = { + geoip.path = lib.mkOption { + type = lib.types.path; + default = "${pkgs.sing-geoip}/share/sing-box/geoip.db"; + defaultText = lib.literalExpression "\${pkgs.sing-geoip}/share/sing-box/geoip.db"; + description = lib.mdDoc '' + The path to the sing-geoip database. + ''; + }; + geosite.path = lib.mkOption { + type = lib.types.path; + default = "${pkgs.sing-geosite}/share/sing-box/geosite.db"; + defaultText = lib.literalExpression "\${pkgs.sing-geosite}/share/sing-box/geosite.db"; + description = lib.mdDoc '' + The path to the sing-geosite database. + ''; + }; + }; + }; + }; + default = { }; + }; + }; + }; + config = lib.mkIf cfg.enable { + networking.firewall.trustedInterfaces = [ "tun0" ]; + + systemd.packages = [ cfg.package ]; + + systemd.services.sing-box = + let + configFile = cfg.stateDir + "/${cfg.configFile.name}"; + in + { + preStart = '' + umask 0077 + mkdir -p /etc/sing-box + if ! [ -e ${configFile} ]; then + ${pkgs.curl}/bin/curl "$(${pkgs.coreutils}/bin/cat ${cfg.configFile.urlFile})" > '${configFile}' + test "${cfg.configFile.hash}" $(${pkgs.coreutils}/bin/sha256sum '${configFile}' | ${pkgs.coreutils}/bin/cut -d ' ' -f 1) + fi + ${utils.genJqSecretsReplacementSnippet cfg.overrideSettings "/etc/sing-box/config.json"} + ${cfg.package}/bin/sing-box merge -c '${configFile}' -c /etc/sing-box/config.json /etc/sing-box/config.json + ''; + wantedBy = [ "multi-user.target" ]; + }; + }; +} + diff --git a/modules/nixos/ssh-tpm-agent.nix b/modules/nixos/ssh-tpm-agent.nix new file mode 100644 index 0000000..f368c46 --- /dev/null +++ b/modules/nixos/ssh-tpm-agent.nix @@ -0,0 +1,48 @@ +# Temporary workaround +{ config, pkgs, lib, ... }: +let + cfg = config.services.ssh-tpm-agent; +in +{ + options = { + services.ssh-tpm-agent.enable = lib.mkEnableOption "TPM supported ssh agent in go"; + }; + config = lib.mkIf cfg.enable { + systemd.user.services.ssh-tpm-agent = { + enable = true; + unitConfig = { + Description = "SSH TPM agent service"; + Documentation = "man:ssh-agent(1) man:ssh-add(1) man:ssh(1)"; + Requires = "ssh-tpm-agent.socket"; + ConditionEnvironment = "!SSH_AGENT_PID"; + }; + serviceConfig = { + Environment = "SSH_AUTH_SOCK=%t/ssh-tpm-agent.socket"; + ExecStart = "${pkgs.ssh-tpm-agent}/bin/ssh-tpm-agent"; + PassEnvironment = "SSH_AGENT_PID"; + SuccessExitStatus = 2; + Type = "simple"; + }; + wants = [ "ssh-tpm-agent.socket" ]; + }; + + systemd.user.sockets.ssh-tpm-agent = { + enable = true; + description = "SSH TPM agent socket"; + socketConfig = { + ListenStream = "%t/ssh-tpm-agent.sock"; + SocketMode = "0600"; + Service = "ssh-tpm-agent.service"; + }; + + wantedBy = [ "sockets.target" ]; + }; + + environment = { + systemPackages = [ pkgs.ssh-tpm-agent ]; + extraInit = '' + export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-tpm-agent.sock" + ''; + }; + }; +} diff --git a/modules/nixos/vaultwarden.nix b/modules/nixos/vaultwarden.nix new file mode 100644 index 0000000..b4c7d04 --- /dev/null +++ b/modules/nixos/vaultwarden.nix @@ -0,0 +1,47 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.custom.vaultwarden; +in +{ + options = { + custom.vaultwarden = { + enable = mkEnableOption "vaultwarden server"; + domain = mkOption { + type = types.str; + default = "bitwarden.example.com"; + description = "Domain name of the vaultwarden server"; + }; + caddy = mkOption { + type = types.bool; + default = true; + description = "Enable Caddy as reverse proxy"; + }; + # TODO: mailserver support + }; + }; + config = mkIf cfg.enable { + services.vaultwarden = { + enable = true; + dbBackend = "sqlite"; + config = { + DOMAIN = "https://${cfg.domain}"; + SIGNUPS_ALLOWED = false; + + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 8222; + + ROCKET_LOG = "critical"; + }; + }; + services.caddy = mkIf cfg.caddy { + enable = true; + virtualHosts."https://${cfg.domain}".extraConfig = '' + reverse_proxy ${config.services.vaultwarden.config.ROCKET_ADDRESS}:${toString config.services.vaultwarden.config.ROCKET_PORT} + ''; + }; + }; +} + diff --git a/nixbuild.net b/nixbuild.net new file mode 100644 index 0000000..77c50ac --- /dev/null +++ b/nixbuild.net @@ -0,0 +1 @@ +ssh-ng://eu.nixbuild.net aarch64-linux - 100 1 big-parallel,benchmark diff --git a/note.md b/note.md new file mode 100644 index 0000000..93a14d6 --- /dev/null +++ b/note.md @@ -0,0 +1,3 @@ +# nix-tree + +Demonstrate disk usage by nix-store path. diff --git a/oci-images/nix-ci-base/flake.lock b/oci-images/nix-ci-base/flake.lock new file mode 100644 index 0000000..82fcde6 --- /dev/null +++ b/oci-images/nix-ci-base/flake.lock @@ -0,0 +1,134 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "libgit2": { + "flake": false, + "locked": { + "lastModified": 1697646580, + "narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=", + "owner": "libgit2", + "repo": "libgit2", + "rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5", + "type": "github" + }, + "original": { + "owner": "libgit2", + "repo": "libgit2", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": "flake-compat", + "libgit2": "libgit2", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1710178469, + "narHash": "sha256-9b9qJ+7rGjLKbIswMf0/2pgUWH/xOlYLk7P4WYNcGDs=", + "owner": "nixos", + "repo": "nix", + "rev": "34807c8906a61219ec2e9132c9cf0bd4d29e1d12", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "2.21.0", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1711124224, + "narHash": "sha256-l0zlN/3CiodvWDtfBOVxeTwYSRz93muVbXWSpaMjXxM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "56528ee42526794d413d6f244648aaee4a7b56c0", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nix": "nix", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/oci-images/nix-ci-base/flake.nix b/oci-images/nix-ci-base/flake.nix new file mode 100644 index 0000000..8e6b882 --- /dev/null +++ b/oci-images/nix-ci-base/flake.nix @@ -0,0 +1,77 @@ +{ + inputs = { + nix.url = "github:/nixos/nix?ref=2.21.0"; + nix.inputs.nixpkgs.follows = "nixpkgs"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + flake-utils, + nix, + nixpkgs, + ... + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = (import nixpkgs) { + inherit system; + }; + lib = pkgs.lib; + in rec { + packages = rec { + # a modified version of the nixos/nix image + # re-using the upstream nix docker image generation code + base = import (nix + "/docker.nix") { + inherit pkgs; + name = "nix-ci-base"; + maxLayers = 10; + extraPkgs = with pkgs; [ + nodejs_20 # nodejs is needed for running most 3rdparty actions + # add any other pre-installed packages here + curl + xz + openssl + coreutils-full + cmake + gnumake + gcc + ]; + # change this is you want + channelURL = "https://nixos.org/channels/nixpkgs-23.11"; + nixConf = { + substituters = [ + "https://mirrors.bfsu.edu.cn/nix-channels/store" + "https://mirrors.ustc.edu.cn/nix-channels/store" + "https://cache.nixos.org/" + + "https://nix-community.cachix.org" + ]; + accept-flake-config = "true"; + log-lines = "300"; + trusted-public-keys = [ + "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + # allow using the new flake commands in our workflows + experimental-features = ["nix-command" "flakes"]; + }; + }; + # make /bin/sleep available on the image + runner = pkgs.dockerTools.buildImage { + name = "nix-runner"; + tag = "2.21.0-pkgs-23.11"; + + fromImage = base; + fromImageName = null; + fromImageTag = "latest"; + + copyToRoot = pkgs.buildEnv { + name = "image-root"; + paths = [pkgs.coreutils-full]; + pathsToLink = ["/bin"]; # add coreutuls (which includes sleep) to /bin + }; + }; + }; + }); +} diff --git a/overlays/add-ime-electron.nix b/overlays/add-ime-electron.nix new file mode 100644 index 0000000..74e94c6 --- /dev/null +++ b/overlays/add-ime-electron.nix @@ -0,0 +1,9 @@ +{ config, pkgs, lib, ... }: + +{ + nixpkgs.overlays = [ + (self: super: { + element-desktop = super.element-desktop.override { commandLineArgs = "--enable-wayland-ime"; }; + }) + ]; +} diff --git a/overlays/add-pkgs.nix b/overlays/add-pkgs.nix new file mode 100644 index 0000000..35b6981 --- /dev/null +++ b/overlays/add-pkgs.nix @@ -0,0 +1,3 @@ +(final: prev: { + oidc-agent = prev.callPackage ./pkgs/oidc-agent { }; +}) diff --git a/overlays/default.nix b/overlays/default.nix new file mode 100644 index 0000000..a94c09a --- /dev/null +++ b/overlays/default.nix @@ -0,0 +1 @@ +final: prev: (import ./add-pkgs.nix) diff --git a/overlays/pkgs/oidc-agent/default.nix b/overlays/pkgs/oidc-agent/default.nix new file mode 100644 index 0000000..42f398e --- /dev/null +++ b/overlays/pkgs/oidc-agent/default.nix @@ -0,0 +1,58 @@ +{ lib +, stdenv +, fetchFromGitHub +, curl +, webkitgtk +, libmicrohttpd +, libsecret +, qrencode +, libsodium +, pkg-config +, help2man +}: + +stdenv.mkDerivation rec { + pname = "oidc-agent"; + version = "5.1.0"; + + src = fetchFromGitHub { + owner = "indigo-dc"; + repo = "oidc-agent"; + rev = "v${version}"; + sha256 = "sha256-cOK/rZ/jnyALLuhDM3+qvwwe4Fjkv8diQBkw7NfVo0c=" + ; + }; + + buildInputs = [ + pkg-config + help2man + ]; + nativeBuildInputs = [ + curl + webkitgtk + libmicrohttpd + libsecret + qrencode + libsodium + ]; + enableParallelBuilding = true; + + installPhase = '' + make -j $NIX_BUILD_CORES PREFIX=$out BIN_PATH=$out LIB_PATH=$out/lib \ + install_bin install_lib install_conf + ''; + postFixup = '' + # Override with patched binary to be used by help2man + cp -r $out/bin/* bin + make install_man PREFIX=$out + ''; + + + meta = with lib; { + description = "oidc-agent for managing OpenID Connect tokens on the command line"; + homepage = "https://github.com/indigo-dc/oidc-agent"; + maintainers = [ ]; + license = licenses.mit; + }; +} + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 6166ab9..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_executable(diffu cli.cpp difftest.cpp gdbstub.cpp loader.cpp main.cpp) -target_link_libraries(diffu PRIVATE gdbstub spdlog::spdlog) -install ( TARGETS diffu ) diff --git a/src/cli.cpp b/src/cli.cpp deleted file mode 100644 index dcbd193..0000000 --- a/src/cli.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "config.hpp" -#include -#include -#include -#include - -int Config::cli_parse(int argc, char **argv) { - CLI::App app; - app.add_option( - "--images-path", images_path, - "Directory containing image files. Search image files in this path.") - ->envname("DIFFU_IMAGES_PATH") - ->check(CLI::ExistingPath); - - app.add_option("-m,--memory", memory_file, - "Image file used to fill up the memory. Relative path to " - "--images-path") - ->required(); - - app.add_option("--ref", refs, "Reference dynamic library")->required(); - - app.add_option("--ref-prefix", refs_prefix, - "Optional prefix for each reference library"); - - app.add_option("--dut", dut, "Design under test")->required(); - - app.add_option("--dut-prefix", dut_prefix, - "Optional prefix for design under test"); - - app.add_option("--listen", gdbstub_addr, "Gdb remote listen address"); - - app.add_flag("-g", use_debugger, "Launch gdb remote stub"); - - app.set_config("-c,--config") - ->transform(CLI::FileOnDefaultPath("difftest.toml")); - - // Default value for refs_prefix - app.callback([&]() { - if (refs_prefix.size() == 0) { - refs_prefix.insert(refs_prefix.end(), refs.size(), ""); - } - }); - - // Check if refs_prefix matches refs. - app.callback([&]() { - if (refs_prefix.size() != refs.size()) { - throw CLI::ParseError( - "Same number of --ref and --ref-prefix must be provided.", EINVAL); - } - }); - - CLI11_PARSE(app, argc, argv); - - return 0; -} diff --git a/src/difftest.cpp b/src/difftest.cpp deleted file mode 100644 index 8a09618..0000000 --- a/src/difftest.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "api.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -Difftest::Difftest(Target &&dut, std::vector &&refs) { - this->dut = std::move(dut); - this->refs = std::move(refs); - - for (const auto &ref : refs) { - if (dut.isa_arch_info->reg_byte != ref.isa_arch_info->reg_byte || - dut.isa_arch_info->reg_num != ref.isa_arch_info->reg_num) { - throw std::runtime_error("Ref and dut must have the same architecture"); - } - } -} - -void Difftest::setup(const std::filesystem::path &memory_file) { - std::ifstream is = std::ifstream(memory_file, std::ios::binary); - - spdlog::debug("Reading image file: {}", memory_file.c_str()); - // Seek to the end to determine the file size - is.seekg(0, std::ios::end); - std::streampos memsize = is.tellg(); - is.seekg(0, std::ios::beg); - - std::vector membuf(memsize); - is.read(membuf.data(), memsize); - is.close(); - - // Initialize memory - // TODO: reset vector should not be hardcoded - // for(auto target : *this) { - for (auto it = this->begin(); it != this->end(); ++it) { - auto &target = *it; - target.ops.init(target.args.data()); - target.ops.write_reg(target.args.data(), 32, 0x80000000UL); - if (target.ops.write_mem(target.args.data(), 0x80000000UL, membuf.size(), - membuf.data()) != 0) - throw std::runtime_error("write_mem failed"); - } -} - -bool Difftest::check_all() { - bool passed = true; - for (auto &ref : refs) { - if (check(dut, ref) == false) - passed = false; - } - return passed; -} - -Difftest::ExecRet Difftest::exec(size_t n, gdb_action_t *ret) { - ExecRet exec_ret = { - .at_breakpoint = false, .do_difftest = true, .check_failed = false}; - while (n--) { - Target *pbreak = &(*(this->begin())); - // TODO: For improvement, use ThreadPool here for concurrent execution? - for (auto it = this->begin(); it != this->end(); ++it) { - auto &target = *it; - *target.do_difftest = true; - target.ops.stepi(target.args.data(), &target.last_res); - spdlog::trace("{} stepped once", target.meta.name); - if (target.is_on_breakpoint()) { - exec_ret.at_breakpoint = true; - pbreak = ⌖ - spdlog::trace("{} on breakpoint", target.meta.name); - continue; - } - exec_ret.do_difftest = *target.do_difftest && exec_ret.do_difftest; - } - - // Do difftest, or sync registers to ref - if (exec_ret.do_difftest) { - if (!check_all()) { - exec_ret.check_failed = true; - } - } else { - size_t pc = 0; - read_reg(32, &pc); - spdlog::debug("Difftest skipped at {}", (void *)pc); - sync_regs_to_ref(); - } - - if (exec_ret.check_failed) { - ret->reason = gdb_action_t::ACT_SHUTDOWN; - } - - if (exec_ret.at_breakpoint) { - ret->reason = pbreak->last_res.reason; - ret->data = pbreak->last_res.data; - break; - } - } - - return exec_ret; -} - -gdb_action_t Difftest::stepi() { - gdb_action_t ret = {.reason = gdb_action_t::ACT_NONE}; - ExecRet exec_result = exec(1, &ret); - return ret; -} - -gdb_action_t Difftest::cont() { - gdb_action_t ret = {.reason = gdb_action_t::ACT_NONE}; - ExecRet exec_ret; - start_run(); - while (!is_halt()) { - exec_ret = exec(1, &ret); - if (exec_ret.at_breakpoint) - break; - }; - return ret; -} - -int Difftest::read_reg(int regno, size_t *value) { - return current_target->ops.read_reg(current_target->args.data(), regno, - value); -} - -int Difftest::write_reg(int regno, size_t value) { - return current_target->ops.write_reg(current_target->args.data(), regno, - value); -} - -int Difftest::sync_regs_to_ref(void) { - std::vector regs; - int ret = 0; - for (int i = 0; i <= get_arch().reg_num; i++) { - size_t r; - ret = dut.ops.read_reg(dut.args.data(), i, &r); - if (ret) - return ret; - regs.push_back(r); - } - for (auto &ref : refs) { - for (int i = 0; i <= get_arch().reg_num; i++) { - ret = ref.ops.write_reg(ref.args.data(), i, regs.at(i)); - if (ret) - return ret; - } - } - spdlog::trace("Applied registers value from dut to ref"); - return ret; -} - -std::string Difftest::list_targets(void) { - std::ostringstream os; - int i = 0; - for (auto it = this->begin(); it != this->end(); ++it, ++i) { - auto &target = *it; - os << i << ": " << target.meta.name << std::endl; - } - os << "current: " << current_target->meta.name << std::endl; - return os.str(); -} - -std::string Difftest::switch_target(int index) { - std::ostringstream os; - int i = 0; - for (auto it = this->begin(); it != this->end(); ++it, ++i) { - auto &target = *it; - if (i == index) { - current_target = ⌖ - os << "Switched to " << current_target->meta.name << std::endl; - return os.str(); - } - } - os << "Invalid target target index: " << index << std::endl; - return os.str(); -} - -int Difftest::read_mem(size_t addr, size_t len, void *val) { - return current_target->ops.read_mem(current_target->args.data(), addr, len, - val); -} - -int Difftest::write_mem(size_t addr, size_t len, void *val) { - return current_target->ops.write_mem(current_target->args.data(), addr, len, - val); -} - -bool Difftest::set_bp(size_t addr, bp_type_t type) { - bool ret = true; - for (auto it = this->begin(); it != this->end(); ++it) { - auto &target = *it; - ret = target.ops.set_bp(target.args.data(), addr, type) && ret; - } - return ret; -} - -bool Difftest::del_bp(size_t addr, bp_type_t type) { - bool ret = true; - for (auto it = this->begin(); it != this->end(); ++it) { - auto &target = *it; - ret = target.ops.del_bp(target.args.data(), addr, type) && ret; - } - return ret; -} diff --git a/src/gdbstub.cpp b/src/gdbstub.cpp deleted file mode 100644 index 2f62a60..0000000 --- a/src/gdbstub.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include -#include -#include -#include -#include -#include -extern "C" { -#include -} - -static std::vector split_into_args(const std::string &command) { - std::istringstream iss(command); - std::vector args; - std::string token; - while (iss >> token) { - args.push_back(token); - } - return args; -} - -extern "C" { -static void difftest_cont(void *args, gdb_action_t *res) { - Difftest *diff = (Difftest *)args; - *res = diff->cont(); -}; - -static void difftest_stepi(void *args, gdb_action_t *res) { - Difftest *diff = (Difftest *)args; - *res = diff->stepi(); -}; - -static int difftest_read_reg(void *args, int regno, size_t *value) { - Difftest *diff = (Difftest *)args; - return diff->read_reg(regno, value); -}; - -static int difftest_write_reg(void *args, int regno, size_t value) { - Difftest *diff = (Difftest *)args; - return diff->write_reg(regno, value); -} - -static int difftest_read_mem(void *args, size_t addr, size_t len, void *val) { - Difftest *diff = (Difftest *)args; - return diff->read_mem(addr, len, val); -} - -static int difftest_write_mem(void *args, size_t addr, size_t len, void *val) { - Difftest *diff = (Difftest *)args; - return diff->write_mem(addr, len, val); -} - -static bool difftest_set_bp(void *args, size_t addr, bp_type_t type) { - Difftest *diff = (Difftest *)args; - return diff->set_bp(addr, type); -} - -static bool difftest_del_bp(void *args, size_t addr, bp_type_t type) { - Difftest *diff = (Difftest *)args; - return diff->del_bp(addr, type); -} - -static void difftest_on_interrupt(void *args) { - Difftest *diff = (Difftest *)args; - puts("interrupt"); - diff->halt(); -} - -static char *gdbstub_monitor(void *args, const char *s) { - Difftest *diff = (Difftest *)args; - spdlog::trace("monitor"); - CLI::App parser; - std::string ret = ""; - - auto sync = parser.add_subcommand("sync", "Sync states between targets") - ->callback([&]() { diff->sync_regs_to_ref(); }); - parser.add_subcommand("list", "List targets.")->callback([&]() { - ret = diff->list_targets(); - }); - parser.add_subcommand("help", "Print help message")->callback([&]() { - ret = parser.help(); - }); - - int target_index = -1; - parser.add_subcommand("switch", "Switch to another target") - ->callback([&]() { ret = diff->switch_target(target_index); }) - ->add_option("target_index", target_index, "Index of the target"); - std::string cmdstr; - int slen = strlen(s); - int ch; - for (int i = 0; i < slen; i += 2) { - sscanf(&s[i], "%02x", &ch); - cmdstr.push_back(ch); - } - - auto arglist = split_into_args(cmdstr); - std::vector argv = {""}; - for (const auto &arg : arglist) { - argv.push_back(static_cast(arg.c_str())); - } - - try { - (parser).parse((argv.size()), (argv.data())); - } catch (const CLI ::ParseError &e) { - std::ostringstream os; - os << "Failed to parse " << cmdstr << std::endl - << parser.help() << std::endl; - ret = os.str(); - } - - if (ret[0] == '\0') { - return NULL; - } else { - std::ostringstream ret_stream; - // Set formatting options for the stream - ret_stream << std::hex << std::setfill('0'); - - for (unsigned char c : ret) { - ret_stream << std::setw(2) << static_cast(c); - } - return strdup(ret_stream.str().c_str()); - } -} -} - -int gdbstub_loop(Difftest *diff, std::string socket_addr) { - target_ops gdbstub_ops = {.cont = difftest_cont, - .stepi = difftest_stepi, - .read_reg = difftest_read_reg, - .write_reg = difftest_write_reg, - .read_mem = difftest_read_mem, - .write_mem = difftest_write_mem, - .set_bp = difftest_set_bp, - .del_bp = difftest_del_bp, - .on_interrupt = difftest_on_interrupt, - .monitor = gdbstub_monitor}; - gdbstub_t gdbstub_priv; - - arch_info_t arch = diff->get_arch(); - - if (!gdbstub_init(&gdbstub_priv, &gdbstub_ops, arch, nullptr, - socket_addr.c_str())) { - spdlog::error("Failed to init socket at: {}", socket_addr); - return false; - } - - spdlog::info("Connected to gdb at {}", socket_addr); - - bool success = gdbstub_run(&gdbstub_priv, diff); - gdbstub_close(&gdbstub_priv); - return !success; -} diff --git a/src/loader.cpp b/src/loader.cpp deleted file mode 100644 index 2a0ab38..0000000 --- a/src/loader.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "api.hpp" -#include -#include -#include -#include - -Target::Target(const std::string &name, const std::string &func_prefix, - const std::filesystem::path &path) { - - meta = {.name = name, - .libpath = path, - .dlhandle = dlopen(path.c_str(), RTLD_NOW)}; - - spdlog::info("Found dlopen API handle for {} at {}", meta.name, - meta.dlhandle); - - if (!meta.dlhandle) { - throw std::runtime_error(dlerror()); - } - -#define LOAD_SYMBOL(ops, handle, prefix, name) \ - do { \ - std::string symbol_name = func_prefix + #name; \ - (ops).name = reinterpret_cast( \ - dlsym((handle), symbol_name.c_str())); \ - if (!((ops).name)) \ - goto load_error; \ - spdlog::debug("Found {} at {}", symbol_name, ((void *)((ops).name))); \ - } while (0); - - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, cont); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, stepi); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, read_reg); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, write_reg); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, read_mem); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, write_mem); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, set_bp); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, del_bp); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, on_interrupt); - LOAD_SYMBOL(ops, meta.dlhandle, func_prefix, init); - - LOAD_SYMBOL(*this, meta.dlhandle, func_prefix, do_difftest); - *do_difftest = true; - - LOAD_SYMBOL(*this, meta.dlhandle, func_prefix, dbg_state_size); - args.resize(*dbg_state_size); - LOAD_SYMBOL(*this, meta.dlhandle, func_prefix, isa_arch_info); -#undef LOAD_SYMBOL - - return; - -load_error: - std::string err = std::string(dlerror()); - dlclose(meta.dlhandle); - throw std::runtime_error(err); -} - -Target::~Target() { dlclose(meta.dlhandle); } - -bool Target::is_on_breakpoint() const { return is_on_breakpoint(last_res); } - -bool Target::is_on_breakpoint(const gdb_action_t &res) const { - if (res.reason == gdb_action_t::ACT_BREAKPOINT || - res.reason == gdb_action_t::ACT_RWATCH || - res.reason == gdb_action_t::ACT_WATCH || - res.reason == gdb_action_t::ACT_WWATCH || - res.reason == gdb_action_t::ACT_SHUTDOWN) { - return true; - } - return false; -} diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 6dea91f..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "api.hpp" -#include "config.hpp" -#include "difftest.hpp" -#include -#include -#include - -int gdbstub_loop(Difftest *, std::string); - -int main(int argc, char **argv) { - spdlog::cfg::load_env_levels(); - Config config; - int ret = 0; - ret = config.cli_parse(argc, argv); - if (ret) - return ret; - - std::vector refs; - Target *dut = new Target{"dut", config.dut_prefix, config.dut}; - auto ref_libpath = config.refs.begin(); - auto ref_prefix = config.refs_prefix.begin(); - while (ref_libpath != config.refs.end() && - ref_prefix != config.refs_prefix.end()) { - refs.emplace_back(ref_libpath->string(), *ref_prefix, *ref_libpath); - ref_libpath++; - ref_prefix++; - } - - Difftest difftest{std::move(*dut), std::move(refs)}; - - std::filesystem::path image_file = config.images_path / config.memory_file; - if (!std::filesystem::exists(image_file)) { - spdlog::error("Cannot find {} in {}.", config.memory_file.c_str(), - config.images_path.c_str()); - } - difftest.setup(image_file); - - if (config.use_debugger) { - gdbstub_loop(&difftest, config.gdbstub_addr); - } else { - gdb_action_t ret = {.reason = gdb_action_t::ACT_NONE}; - Difftest::ExecRet exec_ret; - while (1) { - exec_ret = difftest.exec(1, &ret); - if (exec_ret.check_failed) - return 1; - if (exec_ret.at_breakpoint) - break; - }; - return 0; - } - - return 0; -}