Rework Claude Code config in sandboxed workspaces
Remove credential passing to sandboxes (didn't work well enough). Move onboarding config init from host-side setup into base.nix so each workspace initializes its own Claude config on first boot. Wrap claude command in VM and Incus workspaces to always skip permission prompts.
This commit is contained in:
@@ -11,6 +11,17 @@
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
claudeConfigFile = pkgs.writeText "claude-config.json" (builtins.toJSON {
|
||||
hasCompletedOnboarding = true;
|
||||
theme = "dark";
|
||||
projects = {
|
||||
"/home/googlebot/workspace" = {
|
||||
hasTrustDialogAccepted = true;
|
||||
};
|
||||
};
|
||||
});
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
../shell.nix
|
||||
@@ -112,6 +123,22 @@
|
||||
# Enable fish shell
|
||||
programs.fish.enable = true;
|
||||
|
||||
# Initialize Claude Code config on first boot (skips onboarding, trusts workspace)
|
||||
systemd.services.claude-config-init = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = "googlebot";
|
||||
Group = "users";
|
||||
};
|
||||
script = ''
|
||||
if [ ! -f /home/googlebot/claude-config/.claude.json ]; then
|
||||
cp ${claudeConfigFile} /home/googlebot/claude-config/.claude.json
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Home Manager configuration
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
|
||||
@@ -47,16 +47,10 @@ 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, ... }: {
|
||||
|
||||
@@ -122,45 +122,13 @@ in
|
||||
cfg.workspaces);
|
||||
|
||||
# Automatically generate SSH host keys and directories for all workspaces
|
||||
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" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = "googlebot";
|
||||
Group = "users";
|
||||
};
|
||||
script = ''
|
||||
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
|
||||
'';
|
||||
};
|
||||
}
|
||||
# Per-workspace setup services
|
||||
(lib.mapAttrs'
|
||||
systemd.services = lib.mapAttrs'
|
||||
(name: ws:
|
||||
let
|
||||
serviceName =
|
||||
if ws.type == "vm" then "microvm@${name}"
|
||||
else if ws.type == "incus" then "incus-workspace-${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}";
|
||||
@@ -188,23 +156,9 @@ in
|
||||
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
|
||||
'' + lib.optionalString (ws.type == "incus") ''
|
||||
# Copy credentials for incus (can't use bind mount for files inside another mount)
|
||||
if [ -f /home/googlebot/.claude/.credentials.json ]; then
|
||||
cp /home/googlebot/.claude/.credentials.json /home/googlebot/sandboxed/${name}/claude-config/.credentials.json
|
||||
chown googlebot:users /home/googlebot/sandboxed/${name}/claude-config/.credentials.json
|
||||
chmod 600 /home/googlebot/sandboxed/${name}/claude-config/.credentials.json
|
||||
fi
|
||||
'';
|
||||
}
|
||||
)
|
||||
cfg.workspaces)
|
||||
];
|
||||
cfg.workspaces;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@ let
|
||||
boot.isContainer = true;
|
||||
networking.useHostResolvConf = false;
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
environment.systemPackages = [
|
||||
(lib.hiPrio (pkgs.writeShellScriptBin "claude" ''
|
||||
exec ${pkgs.claude-code}/bin/claude --dangerously-skip-permissions "$@"
|
||||
''))
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
@@ -58,20 +58,11 @@ let
|
||||
networkInterface = { Type = "ether"; };
|
||||
})
|
||||
{
|
||||
# Copy credentials from host mount to per-workspace config
|
||||
systemd.services.claude-credentials = {
|
||||
description = "Copy Claude credentials from host";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "multi-user.target" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
if [ -f /home/googlebot/.claude-credentials/.credentials.json ]; then
|
||||
install -m 600 -o googlebot -g users \
|
||||
/home/googlebot/.claude-credentials/.credentials.json \
|
||||
/home/googlebot/claude-config/.credentials.json
|
||||
fi
|
||||
'';
|
||||
};
|
||||
environment.systemPackages = [
|
||||
(lib.hiPrio (pkgs.writeShellScriptBin "claude" ''
|
||||
exec ${pkgs.claude-code}/bin/claude --dangerously-skip-permissions "$@"
|
||||
''))
|
||||
];
|
||||
|
||||
# MicroVM specific configuration
|
||||
microvm = {
|
||||
@@ -116,14 +107,6 @@ let
|
||||
source = "/home/googlebot/sandboxed/${name}/claude-config";
|
||||
mountPoint = "/home/googlebot/claude-config";
|
||||
}
|
||||
{
|
||||
# Credentials-only directory (read-only)
|
||||
# This directory should contain only .credentials.json
|
||||
proto = "virtiofs";
|
||||
tag = "claude-credentials";
|
||||
source = "/home/googlebot/.claude-credentials";
|
||||
mountPoint = "/home/googlebot/.claude-credentials";
|
||||
}
|
||||
];
|
||||
|
||||
# Writeable overlay for /nix/store
|
||||
|
||||
Reference in New Issue
Block a user