fix: dev vm setup
This commit is contained in:
parent
e73cc0c0f5
commit
b6230a1d29
10 changed files with 218 additions and 31 deletions
42
AGENTS.md
42
AGENTS.md
|
|
@ -1,33 +1,35 @@
|
||||||
# Repository Guidelines
|
# Repository Guidelines
|
||||||
|
|
||||||
## Project Structure & Module Organization
|
## Project Structure & Module Organization
|
||||||
- `flake.nix`/`flake.lock` drive the entire nix-darwin + Home Manager configuration; `macbook-pro` is the only declared host.
|
- `flake.nix` defines shared helpers plus Darwin (`macbook-pro`) and NixOS (`dev-vm`) hosts; `flake.lock` pins inputs.
|
||||||
- `modules/darwin/` contains device-level modules (`system.nix`, `homebrew.nix`, `devtools.nix`). Keep OS services and hardware toggles here.
|
- `modules/darwin/` holds macOS system modules; `modules/nixos/` mirrors that for Linux (base `system.nix` imports `users.nix`, `network.nix`, `ssh.nix`, `containerization.nix`).
|
||||||
- `modules/home/rsydn/` provides the Home Manager profile. Subdirectories `programs/`, `shell/`, and `devtools/` house user apps, Nushell/theming, and language/AI bundles.
|
- Host overlays live under `modules/nixos/hosts/`—e.g., `dev-vm.nix` adds virtio tooling and host-only packages.
|
||||||
- Secrets belong under `secrets/*.sops.yaml`; decrypted payloads are emitted into `~/.config/secrets/` at activation. The cached build outputs in `.cache/` stay untracked.
|
- User configuration is in `modules/home/rsydn/` with subdirectories for `programs/`, `shell/`, and `devtools/`; Darwin layers on `shell/nushell.nix` while Linux sticks to `shell/fish.nix`.
|
||||||
|
- Secrets stay in `secrets/*.sops.yaml`; decrypted files appear under `~/.config/secrets/` at activation and must not be committed.
|
||||||
|
|
||||||
## Build, Test & Development Commands
|
## Build, Test & Development Commands
|
||||||
- `nix develop` — enter the flake dev shell with `git`, `nixfmt-classic`, and Age/SOPS helpers.
|
- `nix develop` – enter the flake dev shell with `git`, `nixfmt-classic`, SOPS/Age helpers.
|
||||||
- `nix fmt` — format every Nix file via the flake’s formatter; run after edits to modules or overlays.
|
- `nix fmt` – format all Nix sources; run before commits touching modules or overlays.
|
||||||
- `XDG_CACHE_HOME=$PWD/.cache nix flake check` — lint and type-check all modules without touching the global cache.
|
- `XDG_CACHE_HOME=$PWD/.cache nix flake check` – lint and eval every host without polluting the global cache.
|
||||||
- `darwin-rebuild --dry-run --flake .#macbook-pro` — validate activation steps and surface breaking changes.
|
- `darwin-rebuild --dry-run --flake .#macbook-pro` / `darwin-rebuild switch --flake .#macbook-pro` – preview or apply macOS changes.
|
||||||
- `darwin-rebuild switch --flake .#macbook-pro` — apply the configuration once checks succeed.
|
- `nix build .#nixosConfigurations.dev-vm.config.system.build.toplevel` – make sure the Linux VM evaluates and builds before switching.
|
||||||
|
|
||||||
## Coding Style & Naming Conventions
|
## Coding Style & Naming Conventions
|
||||||
- Nix sources use two-space indents, trailing commas, and lower-kebab filenames (`shell/nushell.nix`).
|
- Use two-space indentation, trailing commas, and lower-kebab filenames (`shell/nushell.nix`).
|
||||||
- Custom options live in the `rsydn.*` namespace (`rsydn.aiTools`, `rsydn.devTools`). Extend existing option sets instead of scattering ad-hoc attributes.
|
- Declare custom options under the `rsydn.*` namespace (e.g., `rsydn.containerization`, `rsydn.devTools`).
|
||||||
- Prefer declarative package toggles over ad-hoc installers; Nushell, AI CLIs, and prompts are all Home Manager managed.
|
- Prefer declarative package toggles and shared modules over ad-hoc host tweaks; keep host-specific overrides in `hosts/`.
|
||||||
|
|
||||||
## Testing Guidelines
|
## Testing Guidelines
|
||||||
- Run `nix flake check` before every PR or local switch; treat failures as blockers.
|
- Treat `nix flake check` as mandatory before PRs or `switch` operations.
|
||||||
- Capture key outputs (e.g., `darwin-rebuild --dry-run`) for substantial module changes and share in review threads.
|
- Capture key activation output: `darwin-rebuild --dry-run` for macOS, `nix build .#nixosConfigurations.dev-vm…` for the VM, and attach summaries in reviews.
|
||||||
- If you add reusable logic, colocate regression tests beside the module using the `<option-name>.nix` pattern (e.g., `rsydn-ai-tools.nix`).
|
- Co-locate regression tests with the option/module they guard using the `<option-name>.nix` pattern when practical.
|
||||||
|
|
||||||
## Commit & Pull Request Guidelines
|
## Commit & Pull Request Guidelines
|
||||||
- Use short, imperative commit subjects (`add nushell env path hook`); keep each commit scoped to one logical change.
|
- Write short, imperative subjects (`add dev-vm virtualization module`); keep each commit scoped to one change.
|
||||||
- Document validation steps in the PR body (`nix flake check`, dry-run logs) and reference related issues or TODOs.
|
- In PRs, list validation steps (`nix flake check`, host-specific builds) and link related issues or TODOs.
|
||||||
- Include screenshots or terminal snippets when modifying shells, prompts, or visual tooling to show the resulting UI.
|
- Provide screenshots or terminal snippets when altering shell prompts, Tailscale/SSH flows, or other UX-facing pieces.
|
||||||
|
|
||||||
## Security & Configuration Tips
|
## Security & Configuration Tips
|
||||||
- Age keys live at `~/.config/sops/age/keys.txt`; Home Manager generates them if absent. Do not commit decrypted files from `~/.config/secrets/`.
|
- Age keys live at `~/.config/sops/age/keys.txt`; regenerate via Home Manager if missing.
|
||||||
- To access a secret, read the managed file (e.g., `open ~/.config/secrets/openai-api-key | str trim`) and scope the value with `with-env` instead of exporting it globally.
|
- Access secrets by reading the managed files (`open ~/.config/secrets/openai-api-key | str trim`) and scope them with `with-env` instead of exporting globally.
|
||||||
|
- Tailscale and OpenSSH run by default on Linux; rotate auth keys regularly and audit `services.tailscale.extraUpFlags` when enabling exit nodes.
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,12 @@
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
darwinConfigurations = { macbook-pro = mkDarwin { }; };
|
darwinConfigurations = { macbook-pro = mkDarwin { }; };
|
||||||
nixosConfigurations = { };
|
nixosConfigurations = {
|
||||||
|
dev-vm = mkNixos {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
extraModules = [ ./modules/nixos/hosts/dev-vm.nix ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
devShells = forEachSystem (system:
|
devShells = forEachSystem (system:
|
||||||
let
|
let
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@
|
||||||
./secrets.nix
|
./secrets.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.nushell.enable = true;
|
|
||||||
|
|
||||||
programs.git.enable = true;
|
programs.git.enable = true;
|
||||||
|
|
||||||
home.packages = with pkgs; [ docker docker-compose ];
|
home.packages = with pkgs; [ docker docker-compose ];
|
||||||
|
|
@ -39,6 +37,7 @@
|
||||||
ripgrep
|
ripgrep
|
||||||
tmux
|
tmux
|
||||||
tree
|
tree
|
||||||
|
curl
|
||||||
vim
|
vim
|
||||||
wget
|
wget
|
||||||
yq
|
yq
|
||||||
|
|
|
||||||
85
modules/nixos/containerization.nix
Normal file
85
modules/nixos/containerization.nix
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mkEnableOption mkOption mkIf types mkMerge mkAfter optionals;
|
||||||
|
cfg = config.rsydn.containerization;
|
||||||
|
in {
|
||||||
|
options.rsydn.containerization = {
|
||||||
|
docker = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Enable the Docker daemon with sane defaults for development.";
|
||||||
|
};
|
||||||
|
|
||||||
|
autoPrune = mkOption {
|
||||||
|
type = types.submodule {
|
||||||
|
options = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Automatically prune unused Docker data on a schedule.";
|
||||||
|
};
|
||||||
|
dates = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "weekly";
|
||||||
|
description =
|
||||||
|
"Systemd calendar expression for docker system prune.";
|
||||||
|
};
|
||||||
|
flags = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ "--all" "--volumes" ];
|
||||||
|
description = "Extra flags passed to docker system prune.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = { };
|
||||||
|
description = "Settings for automatic Docker pruning.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
k3s = {
|
||||||
|
enable =
|
||||||
|
mkEnableOption "Run a lightweight Kubernetes control plane with k3s.";
|
||||||
|
|
||||||
|
role = mkOption {
|
||||||
|
type = types.enum [ "server" "agent" ];
|
||||||
|
default = "server";
|
||||||
|
description = "Choose whether this node runs as a k3s server or agent.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraFlags = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ "--write-kubeconfig-mode=0644" ];
|
||||||
|
description = "Additional flags to pass to the k3s service.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
(mkIf cfg.docker.enable {
|
||||||
|
virtualisation.docker = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.docker;
|
||||||
|
enableOnBoot = true;
|
||||||
|
autoPrune = {
|
||||||
|
enable = cfg.docker.autoPrune.enable;
|
||||||
|
dates = cfg.docker.autoPrune.dates;
|
||||||
|
flags = cfg.docker.autoPrune.flags;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(mkIf cfg.k3s.enable {
|
||||||
|
services.k3s = {
|
||||||
|
enable = true;
|
||||||
|
role = cfg.k3s.role;
|
||||||
|
extraFlags = cfg.k3s.extraFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts =
|
||||||
|
mkAfter (optionals (cfg.k3s.role == "server") [ 6443 ]);
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
32
modules/nixos/hosts/dev-vm.nix
Normal file
32
modules/nixos/hosts/dev-vm.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{ lib, pkgs, ... }: {
|
||||||
|
networking.hostName = "dev-vm";
|
||||||
|
# Set the baseline NixOS release used for stateful data; bump on rebuilds.
|
||||||
|
system.stateVersion = lib.mkDefault "24.05";
|
||||||
|
|
||||||
|
# Boot loader configuration for VM
|
||||||
|
boot.loader.grub.enable = lib.mkDefault true;
|
||||||
|
boot.loader.grub.device = lib.mkDefault "/dev/vda";
|
||||||
|
|
||||||
|
# Root filesystem configuration for VM
|
||||||
|
fileSystems."/" = lib.mkDefault {
|
||||||
|
device = "/dev/vda1";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
ast-grep
|
||||||
|
ripgrep
|
||||||
|
bat
|
||||||
|
tree
|
||||||
|
zip
|
||||||
|
unzip
|
||||||
|
htop
|
||||||
|
jq
|
||||||
|
psmisc # provides killall and friends
|
||||||
|
gh
|
||||||
|
tree-sitter
|
||||||
|
];
|
||||||
|
|
||||||
|
imports = [ ../virtualization.nix ];
|
||||||
|
}
|
||||||
4
modules/nixos/network.nix
Normal file
4
modules/nixos/network.nix
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{ lib, ... }: {
|
||||||
|
networking.useDHCP = lib.mkDefault true;
|
||||||
|
networking.networkmanager.enable = lib.mkDefault true;
|
||||||
|
}
|
||||||
17
modules/nixos/ssh.nix
Normal file
17
modules/nixos/ssh.nix
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{ lib, ... }: {
|
||||||
|
services.openssh = {
|
||||||
|
enable = lib.mkDefault true;
|
||||||
|
openFirewall = lib.mkDefault true;
|
||||||
|
settings = {
|
||||||
|
PermitRootLogin = "no";
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Run tailscale so the VM can be reached over the mesh network for SSH.
|
||||||
|
services.tailscale = {
|
||||||
|
enable = lib.mkDefault true;
|
||||||
|
useRoutingFeatures = lib.mkDefault "client";
|
||||||
|
extraUpFlags = lib.mkDefault [ "--ssh" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
{ config, pkgs, lib, user, ... }: {
|
{ lib, ... }: {
|
||||||
users.users.${user} = {
|
imports = [ ./users.nix ./network.nix ./ssh.nix ./containerization.nix ];
|
||||||
isNormalUser = lib.mkDefault true;
|
|
||||||
extraGroups = lib.mkDefault [ "wheel" "networkmanager" ];
|
|
||||||
home = lib.mkDefault "/home/${user}";
|
|
||||||
shell = lib.mkDefault pkgs.fish;
|
|
||||||
};
|
|
||||||
|
|
||||||
programs.fish.enable = lib.mkDefault true;
|
nix = {
|
||||||
|
settings.auto-optimise-store = lib.mkDefault true;
|
||||||
|
optimise.automatic = lib.mkDefault true;
|
||||||
|
gc = {
|
||||||
|
automatic = lib.mkDefault true;
|
||||||
|
dates = lib.mkDefault "weekly";
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
modules/nixos/users.nix
Normal file
10
modules/nixos/users.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{ lib, pkgs, user, ... }: {
|
||||||
|
users.users.${user} = {
|
||||||
|
isNormalUser = lib.mkDefault true;
|
||||||
|
extraGroups = lib.mkDefault [ "wheel" "networkmanager" "docker" ];
|
||||||
|
home = lib.mkDefault "/home/${user}";
|
||||||
|
shell = pkgs.fish;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.fish.enable = lib.mkDefault true;
|
||||||
|
}
|
||||||
31
modules/nixos/virtualization.nix
Normal file
31
modules/nixos/virtualization.nix
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{ lib, pkgs, ... }: {
|
||||||
|
# QEMU guest agent provides graceful shutdowns and metadata exchange.
|
||||||
|
# Disabled by default - enable in host overlay if needed.
|
||||||
|
services.qemuGuest.enable = lib.mkDefault false;
|
||||||
|
|
||||||
|
# Spice vdagent handles clipboard sync, display resize, and mouse integration.
|
||||||
|
services.spice-vdagentd.enable = lib.mkDefault true;
|
||||||
|
|
||||||
|
# Keep the VM clock in sync if timesyncd is not already enabled elsewhere.
|
||||||
|
services.timesyncd.enable = lib.mkDefault true;
|
||||||
|
|
||||||
|
# Ensure essential virtio drivers are available early during boot.
|
||||||
|
boot.initrd.kernelModules = lib.mkDefault [
|
||||||
|
"virtio_pci"
|
||||||
|
"virtio_blk"
|
||||||
|
"virtio_net"
|
||||||
|
"virtio_scsi"
|
||||||
|
"virtio_mmio"
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.kernelModules =
|
||||||
|
lib.mkDefault [ "virtio_balloon" "virtio_console" "virtio_rng" ];
|
||||||
|
|
||||||
|
# Provide udev rules to improve virtio device behaviour.
|
||||||
|
services.udev.extraRules = lib.mkDefault ''
|
||||||
|
ACTION=="add", SUBSYSTEM=="virtio", ATTR{device/driver_override}=""
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Pull in a few helper tools useful when tuning the guest.
|
||||||
|
environment.systemPackages = with pkgs; [ spice-vdagent ];
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue