169 lines
3.9 KiB
Nix
169 lines
3.9 KiB
Nix
{
|
|
pkgs,
|
|
lib,
|
|
inputs,
|
|
config,
|
|
...
|
|
}:
|
|
{
|
|
imports = [
|
|
./hardware-configuration.nix
|
|
inputs.self.nixosModules.vm-guest
|
|
inputs.self.nixosModules.seed-ssh
|
|
inputs.self.nixosModules.zsh
|
|
inputs.self.nixosModules.localisation
|
|
];
|
|
|
|
networking.hostName = "sandbox";
|
|
|
|
vm-guest = {
|
|
enable = true;
|
|
headless = true;
|
|
};
|
|
|
|
seed-ssh = {
|
|
enable = true;
|
|
user = "sandbox";
|
|
};
|
|
|
|
zsh.enable = true;
|
|
|
|
localisation = {
|
|
enable = true;
|
|
timeZone = "UTC";
|
|
defaultLocale = "en_US.UTF-8";
|
|
};
|
|
|
|
users = {
|
|
groups.sandbox = {
|
|
gid = 1000;
|
|
};
|
|
users.sandbox = {
|
|
group = "sandbox";
|
|
uid = 1000;
|
|
isNormalUser = true;
|
|
home = "/home/sandbox";
|
|
createHome = true;
|
|
shell = pkgs.zsh;
|
|
extraGroups = [
|
|
"wheel"
|
|
"users"
|
|
];
|
|
};
|
|
};
|
|
|
|
# 9p mounts — silently fail if shares not provided at runtime
|
|
fileSystems."/home/sandbox/projects" = {
|
|
device = "projects";
|
|
fsType = "9p";
|
|
options = [
|
|
"trans=virtio"
|
|
"version=9p2000.L"
|
|
"msize=65536"
|
|
"nofail"
|
|
"x-systemd.automount"
|
|
"x-systemd.device-timeout=2s"
|
|
];
|
|
};
|
|
|
|
fileSystems."/mnt/host-claude" = {
|
|
device = "hostclaude";
|
|
fsType = "9p";
|
|
options = [
|
|
"trans=virtio"
|
|
"version=9p2000.L"
|
|
"msize=65536"
|
|
"nofail"
|
|
"x-systemd.device-timeout=2s"
|
|
];
|
|
};
|
|
|
|
fileSystems."/mnt/host-home" = {
|
|
device = "hosthome";
|
|
fsType = "9p";
|
|
options = [
|
|
"trans=virtio"
|
|
"version=9p2000.L"
|
|
"msize=65536"
|
|
"nofail"
|
|
"x-systemd.device-timeout=2s"
|
|
"ro"
|
|
];
|
|
};
|
|
|
|
# pre-auth claude-code from host config
|
|
systemd.services.claude-auth = {
|
|
description = "Copy claude-code credentials from host mount";
|
|
after = [
|
|
"mnt-host\\x2dclaude.mount"
|
|
"mnt-host\\x2dhome.mount"
|
|
];
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart =
|
|
let
|
|
mountpoint = "${pkgs.util-linux}/bin/mountpoint";
|
|
in
|
|
pkgs.writeShellScript "claude-auth" ''
|
|
# wait for mounts to appear
|
|
for i in $(seq 1 10); do
|
|
${mountpoint} -q /mnt/host-claude && break
|
|
${mountpoint} -q /mnt/host-home && break
|
|
sleep 1
|
|
done
|
|
|
|
if ! ${mountpoint} -q /mnt/host-claude && ! ${mountpoint} -q /mnt/host-home; then
|
|
echo "no host mounts found, skipping"
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p /home/sandbox/.claude
|
|
if ${mountpoint} -q /mnt/host-claude; then
|
|
cp -a /mnt/host-claude/. /home/sandbox/.claude/
|
|
fi
|
|
if ${mountpoint} -q /mnt/host-home; then
|
|
cp /mnt/host-home/.claude.json /home/sandbox/.claude.json || true
|
|
fi
|
|
chown -R sandbox:sandbox /home/sandbox/.claude /home/sandbox/.claude.json 2>/dev/null || true
|
|
'';
|
|
};
|
|
};
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
claude-code
|
|
git
|
|
];
|
|
|
|
# image builder VM needs more than the default 1G to copy closure
|
|
image.modules.qemu =
|
|
{ config, modulesPath, ... }:
|
|
{
|
|
system.build.image = lib.mkForce (
|
|
import (modulesPath + "/../lib/make-disk-image.nix") {
|
|
inherit lib config pkgs;
|
|
inherit (config.virtualisation) diskSize;
|
|
inherit (config.image) baseName format;
|
|
partitionTableType = if config.image.efiSupport then "efi" else "legacy";
|
|
memSize = 16384;
|
|
}
|
|
);
|
|
};
|
|
image.modules.qemu-efi =
|
|
{ config, modulesPath, ... }:
|
|
{
|
|
system.build.image = lib.mkForce (
|
|
import (modulesPath + "/../lib/make-disk-image.nix") {
|
|
inherit lib config pkgs;
|
|
inherit (config.virtualisation) diskSize;
|
|
inherit (config.image) baseName format;
|
|
partitionTableType = if config.image.efiSupport then "efi" else "legacy";
|
|
memSize = 16384;
|
|
}
|
|
);
|
|
};
|
|
|
|
system.stateVersion = "25.11";
|
|
}
|