feat: VM disk sandboxing with full VM isolation
- Add VM provisioning module (vm-provisioner.js) with 3 platform strategies: * Windows: WSL2 distro with fixed VHDX * macOS: Lima VM with fixed disk * Linux: loopback ext4 image - Add IPC handlers (vm-ipc.js) for Electron wizard integration - Add disk budget wizard step (disk-budget-step.js) with presets - Wire VM handlers into main process (index.js) - Add preload bridges for VM operations - Update install.sh with --disk-size flag and sandbox functions - Add disk safety env vars to docker-compose template - Add memory limits to prevent OOM during startup Users can now pick a disk budget (10GB/30GB/100GB/custom) and DashCaddy creates a sandboxed VM that physically cannot exceed that limit. Uninstall cleanly removes the entire VM/disk with zero leakage.
This commit is contained in:
@@ -10,6 +10,7 @@ process.on('uncaughtException', (error) => {
|
||||
});
|
||||
|
||||
let mainWindow;
|
||||
const { registerVMHandlers } = require('./vm-ipc');
|
||||
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
@@ -47,9 +48,23 @@ function createWindow() {
|
||||
}
|
||||
|
||||
// App lifecycle handlers
|
||||
// --- Disk space check (for VM disk budget step) ---
|
||||
ipcMain.handle('get-disk-space', async (event, targetPath) => {
|
||||
try {
|
||||
const stats = await require('fs').promises.statfs(targetPath || '/');
|
||||
return {
|
||||
free: stats.bavail * stats.bsize,
|
||||
total: stats.blocks * stats.bsize,
|
||||
};
|
||||
} catch (e) {
|
||||
return { free: 0, total: 0, error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
|
||||
registerVMHandlers(mainWindow);
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow();
|
||||
|
||||
@@ -95,6 +95,24 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
ipcRenderer.on('uninstall-error', (event, data) => callback(data));
|
||||
},
|
||||
|
||||
|
||||
// --- VM Disk Sandbox ---
|
||||
vmGetPresets: () => ipcRenderer.invoke('vm:get-presets'),
|
||||
vmGetStatus: () => ipcRenderer.invoke('vm:get-status'),
|
||||
vmProvision: (opts) => ipcRenderer.invoke('vm:provision', opts),
|
||||
vmDestroy: (opts) => ipcRenderer.invoke('vm:destroy', opts),
|
||||
vmExportData: (opts) => ipcRenderer.invoke('vm:export-data', opts),
|
||||
getDiskSpace: (path) => ipcRenderer.invoke('get-disk-space', path),
|
||||
onVMProgress: (callback) => {
|
||||
ipcRenderer.on('vm:progress', (event, data) => callback(data));
|
||||
},
|
||||
onVMComplete: (callback) => {
|
||||
ipcRenderer.on('vm:complete', (event, data) => callback(data));
|
||||
},
|
||||
onVMError: (callback) => {
|
||||
ipcRenderer.on('vm:error', (event, data) => callback(data));
|
||||
},
|
||||
|
||||
// Remove listeners
|
||||
removeListener: (channel) => {
|
||||
ipcRenderer.removeAllListeners(channel);
|
||||
|
||||
Reference in New Issue
Block a user