diff --git a/AGENT.md b/AGENT.md new file mode 100644 index 0000000..2b5e690 --- /dev/null +++ b/AGENT.md @@ -0,0 +1,31 @@ +# AGENT.md + +이 저장소는 NixOS 26.11을 기준으로 관리하는 개인 Nix flake입니다. + +## 반드시 지킬 규칙 + +- 저장소 안의 `default.nix` 대부분의 경우에는 파일은 수정하지 않습니다. 하지만 필요한 경우 수정하세요. 호스트 진입점과 모듈 진입점이므로, 변경이 필요하면 이를 참조하는 다른 파일이나 진입점 밖의 모듈을 수정합니다. +- 기존 작업 트리의 변경사항을 덮어쓰지 않습니다. 작업 전 `git status --short`와 `git diff`를 확인합니다. +- `hosts/**/secrets/` 아래의 비밀 파일을 복호화하거나 내용을 출력하지 않습니다. +- 호스트별 설정은 `hosts/`, 재사용 가능한 NixOS/Home Manager 설정은 `modules/`, 패키지 오버레이는 `overlays/`에 둡니다. +- 새 호스트를 추가하거나 flake 출력 구조를 바꿀 때는 기존 `default.nix`를 수정하지 않고, 필요한 경우 그 파일을 호출하는 `flake.nix` 또는 호스트의 비-default 모듈만 조정합니다. + +## 구조 + +- `flake.nix`: 입력, 오버레이, `nixosConfigurations`와 `darwinConfigurations`를 정의합니다. +- `hosts/machine/`: 데스크톱·노트북·WSL 호스트입니다. +- `hosts/server/`: 서버 호스트와 서비스 설정입니다. +- `modules/mizukios/`: 공통 NixOS 기반 및 기능 모듈입니다. +- `modules/home/`: 공통 Home Manager 모듈입니다. +- `assets/`: 설정에서 참조하는 이미지와 테마 자산입니다. + +## 검증 + +가능한 경우 다음 순서로 확인합니다. + +```sh +git diff --check +nix flake check --no-build +``` + +Nix 전역 캐시 권한이나 네트워크 문제로 평가가 실패할 수 있으므로, 코드 오류와 환경 오류를 구분해 보고합니다. 포맷터가 별도로 설정되어 있지 않다면 자동 포맷으로 대규모 파일을 재작성하지 말고, 변경 범위를 작게 유지합니다. diff --git a/README.md b/README.md index 7b18145..9ea3456 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ -nr -clean -update +# nix-flakes + +```sh +nix flake check --no-build + +sudo nixos-rebuild switch --flake .#<호스트> + +nix flake update +``` + +`nr`, `clean`, `update` diff --git a/hosts/machine/mizuki/configuration.nix b/hosts/machine/mizuki/configuration.nix index 7263e20..c002e1f 100644 --- a/hosts/machine/mizuki/configuration.nix +++ b/hosts/machine/mizuki/configuration.nix @@ -1,10 +1,11 @@ -{ pkgs, inputs, ... }: +{ lib, pkgs, inputs, ... }: { imports = [ ./hardware-configuration.nix "${inputs.self}/modules/mizukios/base" "${inputs.self}/modules/mizukios/features/system/boot.nix" + "${inputs.self}/modules/mizukios/features/system/sbctl.nix" "${inputs.self}/modules/mizukios/features/fonts.nix" "${inputs.self}/modules/mizukios/features/packages.nix" "${inputs.self}/modules/mizukios/features/plasma.nix" @@ -66,5 +67,18 @@ hardware.nvidia-container-toolkit.enable = true; + programs.obs-studio = { + # OBS itself is managed by Home Manager; enable the NixOS module so it + # installs and loads v4l2loopback for the virtual camera. + enable = true; + package = null; + enableVirtualCamera = true; + }; + + # video0 and video1 are occupied by the physical camera devices. + boot.extraModprobeConfig = lib.mkForce '' + options v4l2loopback devices=1 video_nr=2 card_label="OBS Cam" exclusive_caps=1 + ''; + system.stateVersion = "26.05"; } diff --git a/hosts/machine/mizuki/home/default.nix b/hosts/machine/mizuki/home/default.nix index b4ff690..586583a 100644 --- a/hosts/machine/mizuki/home/default.nix +++ b/hosts/machine/mizuki/home/default.nix @@ -34,6 +34,7 @@ ./config/plasma.nix "${inputs.self}/modules/home/discord/linux.nix" "${inputs.self}/modules/home/obs-studio.nix" + "${inputs.self}/modules/home/kdenlive.nix" "${inputs.self}/modules/home/devtool/vscode.nix" "${inputs.self}/modules/home/devtool/ciscopackettracer.nix" "${inputs.self}/modules/home/ssh.nix" diff --git a/hosts/machine/mizuki/home/packages.nix b/hosts/machine/mizuki/home/packages.nix index 9246ca1..797b071 100644 --- a/hosts/machine/mizuki/home/packages.nix +++ b/hosts/machine/mizuki/home/packages.nix @@ -13,8 +13,6 @@ with pkgs; jetbrains.rider davinci-resolve - kdePackages.kdenlive - android-tools android-cli diff --git a/hosts/machine/ribbon/configuration.nix b/hosts/machine/ribbon/configuration.nix index ec8907a..d0a5bef 100644 --- a/hosts/machine/ribbon/configuration.nix +++ b/hosts/machine/ribbon/configuration.nix @@ -2,7 +2,7 @@ { imports = [ "${inputs.self}/modules/mizukios/base" - "${inputs.self}/modules/mizukios/features/ssh.nix" + "${inputs.self}/modules/mizukios/features/remote/ssh.nix" ]; wsl.enable = true; diff --git a/hosts/server/hikari/default/configuration.nix b/hosts/server/hikari/default/configuration.nix index 0f4e0cb..871c746 100644 --- a/hosts/server/hikari/default/configuration.nix +++ b/hosts/server/hikari/default/configuration.nix @@ -1,5 +1,9 @@ -{ pkgs, inputs, ... }: +{ modulesPath, pkgs, inputs, ... }: { + # RustFS is provided by the pinned flake input below; NixOS 26.11 also + # ships a module with the same option namespace. + disabledModules = [ "${modulesPath}/services/web-servers/rustfs.nix" ]; + imports = [ ./hardware-configuration.nix "${inputs.self}/modules/mizukios/base" diff --git a/modules/home/discord/linux.nix b/modules/home/discord/linux.nix index 3eca842..2eb7696 100644 --- a/modules/home/discord/linux.nix +++ b/modules/home/discord/linux.nix @@ -1,18 +1,21 @@ { pkgs, inputs, - lib, - options, ... }: { imports = [ inputs.nixcord.homeModules.nixcord ]; - # imports = [ inputs.nixcord.nixosModules.nixcord ]; programs.nixcord = { enable = true; discord = { - branch = "stable"; + branches = [ "stable" ]; + # Electron's Vulkan backend crashes on the NVIDIA render node under + # native Wayland. Keep Wayland and hardware acceleration, but use GL. + commandLineArgs = [ + "--use-gl=angle" + "--use-angle=gl" + ]; vencord.enable = false; equicord.enable = true; krisp.enable = true; @@ -25,10 +28,4 @@ home.packages = with pkgs; [ discord-gamesdk ]; - - # home.activation.krispPatch = lib.mkIf (!pkgs.stdenv.isDarwin) ( - # lib.hm.dag.entryAfter [ "writeBoundary" ] '' - # ${krisp-patcher}/bin/krisp-patcher $(${pkgs.findutils}/bin/find $HOME/.config/discord/ -name "discord_krisp.node" -path "*/modules/discord_krisp/*") || true - # '' - # ); } diff --git a/modules/home/firefox-devedition.nix b/modules/home/firefox-devedition.nix index 337eeb4..f8fddcf 100644 --- a/modules/home/firefox-devedition.nix +++ b/modules/home/firefox-devedition.nix @@ -2,6 +2,8 @@ { programs.firefox = { enable = true; + # Keep the pre-26.05 Home Manager location until the profile is migrated. + configPath = ".mozilla/firefox"; package = pkgs.firefox-devedition; policies = { diff --git a/modules/home/kdenlive.nix b/modules/home/kdenlive.nix new file mode 100644 index 0000000..ffcb530 --- /dev/null +++ b/modules/home/kdenlive.nix @@ -0,0 +1,80 @@ +{ lib, pkgs, ... }: +let + pythonPackages = pkgs.python3Packages; + + # Vosk is not present in the current nixpkgs revision, although it is one + # of the backends shipped with Kdenlive. Package its upstream manylinux + # wheel until it is available from nixpkgs. + vosk = pythonPackages.buildPythonPackage rec { + pname = "vosk"; + version = "0.3.45"; + format = "wheel"; + + src = pkgs.fetchPypi { + inherit pname version format; + python = "py3"; + dist = "py3"; + platform = "manylinux_2_12_x86_64.manylinux2010_x86_64"; + hash = "sha256-JeAlCTxDmdcnj1Q1aO2MxUYKw6S/SMI2c6zh4l0mYZ8="; + }; + + # The upstream wheel bundles libvosk.so without an RPATH. Patch it to + # the Nix C++ runtime so importing vosk works outside a FHS environment. + nativeBuildInputs = [ pkgs.autoPatchelfHook ]; + buildInputs = [ pkgs.stdenv.cc.cc.lib ]; + + propagatedBuildInputs = with pythonPackages; [ + cffi + srt + requests + tqdm + websockets + ]; + + meta = with pkgs.lib; { + description = "Offline open source speech recognition toolkit"; + homepage = "https://alphacephei.com/vosk/"; + license = licenses.asl20; + }; + }; + + # Kdenlive's speech-to-text scripts are launched through + # /usr/bin/env python3. Keep this environment private to Kdenlive so the + # other Python environments installed on the system remain independent. + kdenlivePython = pkgs.python3.withPackages ( + pythonPackages: with pythonPackages; [ + pip + numba + openai-whisper + srt + torch + vosk + ] + ); + + kdenlive = pkgs.kdePackages.kdenlive.overrideAttrs (old: { + nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ pkgs.makeWrapper ]; + postFixup = (old.postFixup or "") + '' + wrapProgram $out/bin/kdenlive \ + --prefix PATH : ${kdenlivePython}/bin \ + --set PYTHONNOUSERSITE 1 + ''; + }); +in +{ + home.packages = [ kdenlive ]; + + # Kdenlive otherwise prefers its mutable ~/.local/share/kdenlive/venv. + # That venv was created by pip and its native Torch libraries do not have + # the Nix runtime paths. Point Kdenlive at the immutable environment above. + home.activation.kdenliveSpeechPython = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + run ${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 \ + --file "$HOME/.config/kdenliverc" \ + --group speech \ + --key speech_system_python true + run ${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 \ + --file "$HOME/.config/kdenliverc" \ + --group speech \ + --key speech_system_python_path ${kdenlivePython}/bin/python3 + ''; +} diff --git a/modules/mizukios/features/packages/docker2libc.nix b/modules/mizukios/features/packages/docker2libc.nix index 04a0ee8..cd51177 100644 --- a/modules/mizukios/features/packages/docker2libc.nix +++ b/modules/mizukios/features/packages/docker2libc.nix @@ -14,7 +14,7 @@ pkgs.writeShellApplication { #!/usr/bin/env bash set -euo pipefail - image="${1:-tmp-elf-extract}" + image="''${1:-tmp-elf-extract}" docker build -t "$image" . @@ -30,8 +30,8 @@ pkgs.writeShellApplication { [ -n "$libc_path" ] || { echo "libc.so.6 not found" >&2; exit 1; } [ -n "$ld_path" ] || { echo "ld-linux not found" >&2; exit 1; } - docker cp -L "${cid}:${libc_path}" ./libc.so.6 - docker cp -L "${cid}:${ld_path}" ./ld-linux-x86-64.so.2 + docker cp -L "''${cid}:''${libc_path}" ./libc.so.6 + docker cp -L "''${cid}:''${ld_path}" ./ld-linux-x86-64.so.2 file libc.so.6 ld-linux-x86-64.so.2 ls -lh libc.so.6 ld-linux-x86-64.so.2 diff --git a/modules/mizukios/features/system/boot.nix b/modules/mizukios/features/system/boot.nix index 5e416b1..00d2822 100644 --- a/modules/mizukios/features/system/boot.nix +++ b/modules/mizukios/features/system/boot.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ config, pkgs, ... }: { # boot.plymouth.enable = true; boot.loader = { @@ -10,6 +10,36 @@ device = "nodev"; enableCryptodisk = true; + # GRUB is signed directly with the sbctl db key. Do not use the shim + # verifier here; it would reject the NixOS kernel/initrd chain before + # GRUB can load it. + extraGrubInstallArgs = [ + "--modules=tpm" + "--disable-shim-lock" + ]; + + # Sign the freshly installed GRUB and NixOS kernels before rebooting. + # Key creation/enrollment is intentionally a one-time manual step and + # is skipped until /var/lib/sbctl/keys/db/db.key exists. + extraInstallCommands = '' + if [ -r /var/lib/sbctl/keys/db/db.key ]; then + for file in \ + "${config.boot.loader.efi.efiSysMountPoint}/EFI/NixOS-boot/grubx64.efi" \ + "${config.boot.loader.efi.efiSysMountPoint}/EFI/BOOT/BOOTX64.EFI"; do + if [ -f "$file" ]; then + ${pkgs.sbctl}/bin/sbctl sign -s "$file" || true + fi + done + + if [ -d "${config.boot.loader.efi.efiSysMountPoint}/kernels" ]; then + ${pkgs.findutils}/bin/find \ + "${config.boot.loader.efi.efiSysMountPoint}/kernels" \ + -type f -name '*-bzImage' \ + -exec ${pkgs.sbctl}/bin/sbctl sign -s {} \; || true + fi + fi + ''; + # extraInstallCommands = '' # mkdir -p /boot/EFI/BOOT diff --git a/modules/mizukios/features/system/sbctl.nix b/modules/mizukios/features/system/sbctl.nix index be2790a..97edd51 100644 --- a/modules/mizukios/features/system/sbctl.nix +++ b/modules/mizukios/features/system/sbctl.nix @@ -1,37 +1,21 @@ -{ pkgs, config, ... }: +{ config, pkgs, ... }: { environment.systemPackages = with pkgs; [ sbctl ]; - - # The 99 here ensures that this runs AFTER the grub activation scripts. - system.activationScripts."99-sign-all" = { + + # Keep the signing database up to date if a kernel is generated without a + # GRUB reinstall. GRUB itself is signed by boot.nix after installation. + system.activationScripts."99-sign-secure-boot-kernels" = { text = '' - if [ "$NIXOS_ACTION" = "switch" ] || [ "$NIXOS_ACTION" = "boot" ]; then - # `sbctl verify --json` returns "null" if there is an error, - # empty string if there are no files in the database. - if [ "$(${pkgs.sbctl}/bin/sbctl verify --json)" != "null" ]; then - - echo "Signing all EFI binaries with sbctl..." - - ESP="${config.boot.loader.efi.efiSysMountPoint}" - readarray -t files < <(find "$ESP" -type f -iname "*.efi" -o -iname "*bzImage") - - # Removing all the files first. - for file in "${"$"}{files[@]}"; do - echo "Removing from sbctl: $file" - # The `|| true` part is because otherwise some files might not exist and - # the script would return an error. - ${pkgs.sbctl}/bin/sbctl remove-file "$file" >/dev/null 2>&1 || true - done - - for file in "${"$"}{files[@]}"; do - echo "Signing with sbctl: $file" - ${pkgs.sbctl}/bin/sbctl sign -s "$file" >/dev/null 2>&1 - done - + if [ -r /var/lib/sbctl/keys/db/db.key ]; then + if [ -d "${config.boot.loader.efi.efiSysMountPoint}/kernels" ]; then + ${pkgs.findutils}/bin/find \ + "${config.boot.loader.efi.efiSysMountPoint}/kernels" \ + -type f -name '*-bzImage' \ + -exec ${pkgs.sbctl}/bin/sbctl sign -s {} \; || true fi fi ''; }; -} \ No newline at end of file +}