diff --git a/common/sandboxed-workspace/container.nix b/common/sandboxed-workspace/container.nix index eb759c8..642fcfc 100644 --- a/common/sandboxed-workspace/container.nix +++ b/common/sandboxed-workspace/container.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: # Container-specific configuration for sandboxed workspaces using systemd-nspawn # This module is imported by default.nix for workspaces with type = "container" @@ -47,10 +47,16 @@ in hostPath = "/home/googlebot/sandboxed/${name}/ssh-host-keys"; isReadOnly = false; }; + # Per-workspace claude config for isolated session data "/home/googlebot/claude-config" = { hostPath = "/home/googlebot/sandboxed/${name}/claude-config"; isReadOnly = false; }; + # Share credentials from host (read-only) + "/home/googlebot/claude-config/.credentials.json" = { + hostPath = "/home/googlebot/.claude/.credentials.json"; + isReadOnly = true; + }; }; config = { config, lib, pkgs, ... }: { @@ -65,6 +71,8 @@ in ]; networking.useHostResolvConf = false; + + nixpkgs.config.allowUnfree = true; }; }) containerWorkspaces; diff --git a/common/sandboxed-workspace/default.nix b/common/sandboxed-workspace/default.nix index 2753e02..cd8924f 100644 --- a/common/sandboxed-workspace/default.nix +++ b/common/sandboxed-workspace/default.nix @@ -118,40 +118,79 @@ in cfg.workspaces); # Automatically generate SSH host keys and directories for all workspaces - systemd.services = lib.mapAttrs' - (name: ws: - let - serviceName = if ws.type == "vm" then "microvm@${name}" else "container@${name}"; - in - lib.nameValuePair "workspace-${name}-setup" { - description = "Setup directories and SSH keys for workspace ${name}"; + systemd.services = lib.mkMerge [ + # Create credentials-only directory for VMs (symlinks to actual credentials) + { + claude-credentials-dir = { + description = "Setup Claude credentials directory for VM workspaces"; wantedBy = [ "multi-user.target" ]; - before = [ "${serviceName}.service" ]; - serviceConfig = { Type = "oneshot"; RemainAfterExit = true; + User = "googlebot"; + Group = "users"; }; - script = '' - # Create directories if they don't exist - mkdir -p /home/googlebot/sandboxed/${name}/workspace - mkdir -p /home/googlebot/sandboxed/${name}/ssh-host-keys - mkdir -p /home/googlebot/sandboxed/${name}/claude-config - - # Fix ownership - chown -R googlebot:users /home/googlebot/sandboxed/${name} - - # Generate SSH host key if it doesn't exist - if [ ! -f /home/googlebot/sandboxed/${name}/ssh-host-keys/ssh_host_ed25519_key ]; then - ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" \ - -f /home/googlebot/sandboxed/${name}/ssh-host-keys/ssh_host_ed25519_key - chown googlebot:users /home/googlebot/sandboxed/${name}/ssh-host-keys/ssh_host_ed25519_key* - echo "Generated SSH host key for workspace ${name}" + mkdir -p /home/googlebot/.claude-credentials + # Copy credentials file (not symlink - virtiofs can't follow host symlinks) + if [ -f /home/googlebot/.claude/.credentials.json ]; then + cp /home/googlebot/.claude/.credentials.json /home/googlebot/.claude-credentials/.credentials.json + chmod 600 /home/googlebot/.claude-credentials/.credentials.json fi ''; - } - ) - cfg.workspaces; + }; + } + # Per-workspace setup services + (lib.mapAttrs' + (name: ws: + let + serviceName = if ws.type == "vm" then "microvm@${name}" else "container@${name}"; + claudeConfig = builtins.toJSON { + hasCompletedOnboarding = true; + theme = "dark"; + projects = { + "/home/googlebot/workspace" = { + hasTrustDialogAccepted = true; + }; + }; + }; + in + lib.nameValuePair "workspace-${name}-setup" { + description = "Setup directories and SSH keys for workspace ${name}"; + wantedBy = [ "multi-user.target" ]; + before = [ "${serviceName}.service" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + script = '' + # Create directories if they don't exist + mkdir -p /home/googlebot/sandboxed/${name}/workspace + mkdir -p /home/googlebot/sandboxed/${name}/ssh-host-keys + mkdir -p /home/googlebot/sandboxed/${name}/claude-config + + # Fix ownership + chown -R googlebot:users /home/googlebot/sandboxed/${name} + + # Generate SSH host key if it doesn't exist + if [ ! -f /home/googlebot/sandboxed/${name}/ssh-host-keys/ssh_host_ed25519_key ]; then + ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" \ + -f /home/googlebot/sandboxed/${name}/ssh-host-keys/ssh_host_ed25519_key + chown googlebot:users /home/googlebot/sandboxed/${name}/ssh-host-keys/ssh_host_ed25519_key* + echo "Generated SSH host key for workspace ${name}" + fi + + # Create claude-code config to skip onboarding and trust ~/workspace + if [ ! -f /home/googlebot/sandboxed/${name}/claude-config/.claude.json ]; then + echo '${claudeConfig}' > /home/googlebot/sandboxed/${name}/claude-config/.claude.json + chown googlebot:users /home/googlebot/sandboxed/${name}/claude-config/.claude.json + fi + ''; + } + ) + cfg.workspaces) + ]; }; }