From 2a0c62946822684f8c81f037a244203546550fdc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 28 Sep 2026 06:00:27 +0000 Subject: [PATCH 1/5] Initial plan From 6d747a7110441d8ae012fdb6151ac03197cd2145 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 28 Sep 2026 06:05:25 +0000 Subject: [PATCH 2/5] Handle Ubuntu 24+ Electron sandbox startup Co-authored-by: highperformancecoder <3075825+highperformancecoder@users.noreply.github.com> --- .../src/app/app.sandbox.spec.ts | 23 ++++++++++++++++ gui-js/apps/minsky-electron/src/app/app.ts | 6 +++++ .../minsky-electron/src/app/linux-sandbox.ts | 27 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts create mode 100644 gui-js/apps/minsky-electron/src/app/linux-sandbox.ts diff --git a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts new file mode 100644 index 000000000..4d2418458 --- /dev/null +++ b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts @@ -0,0 +1,23 @@ +import { requiresNoSandboxOnLinux } from './linux-sandbox'; + +describe('requiresNoSandboxOnLinux', () => { + it('returns true for Ubuntu 24.04', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="24.04"\n')).toBe(true); + }); + + it('returns true for Ubuntu 26.04', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="26.04"\n')).toBe(true); + }); + + it('returns false for Ubuntu 22.04', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="22.04"\n')).toBe(false); + }); + + it('returns false for non-Ubuntu Linux', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID=debian\nVERSION_ID="12"\n')).toBe(false); + }); + + it('returns false for non-Linux platforms', () => { + expect(requiresNoSandboxOnLinux('darwin', 'ID=ubuntu\nVERSION_ID="24.04"\n')).toBe(false); + }); +}); diff --git a/gui-js/apps/minsky-electron/src/app/app.ts b/gui-js/apps/minsky-electron/src/app/app.ts index 42ad6a955..7b21c2943 100644 --- a/gui-js/apps/minsky-electron/src/app/app.ts +++ b/gui-js/apps/minsky-electron/src/app/app.ts @@ -16,6 +16,7 @@ import { ApplicationMenuManager } from './managers/ApplicationMenuManager'; import { BookmarkManager } from './managers/BookmarkManager'; import { CommandsManager } from './managers/CommandsManager'; import { HelpFilesManager } from './managers/HelpFilesManager'; +import { requiresNoSandboxOnLinux } from './linux-sandbox'; import { RecentFilesManager } from './managers/RecentFilesManager'; import { StoreManager } from './managers/StoreManager'; import { WindowManager } from './managers/WindowManager'; @@ -238,6 +239,11 @@ export default class App { // makes the code easier to write tests for App.BrowserWindow = browserWindow; App.application = app; + + if (requiresNoSandboxOnLinux()) { + app.commandLine.appendSwitch('no-sandbox'); + log.info('Enabled --no-sandbox for Ubuntu 24.04+ compatibility'); + } // Rendering was not working on some window's machines without disabling gpu if (process.platform === 'win32') { diff --git a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts new file mode 100644 index 000000000..1f7f7f8d0 --- /dev/null +++ b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts @@ -0,0 +1,27 @@ +import { existsSync, readFileSync } from 'fs'; + +function parseOsReleaseValue(osReleaseContent: string, key: string): string { + const match=osReleaseContent.match(new RegExp(`^${key}=(.*)$`, 'm')); + return match? match[1].trim().replace(/^['"]|['"]$/g, '').toLowerCase(): ''; +} + +export function requiresNoSandboxOnLinux( + platform=process.platform, + osReleaseContent?: string +): boolean { + if (platform!=='linux') return false; + try { + if (!osReleaseContent) { + let osRelease='/etc/os-release'; + if (existsSync(process.resourcesPath+'/os-release')) + osRelease=process.resourcesPath+'/os-release'; + osReleaseContent=readFileSync(osRelease, 'utf8'); + } + const distro=parseOsReleaseValue(osReleaseContent, 'ID'); + const versionId=parseOsReleaseValue(osReleaseContent, 'VERSION_ID'); + const versionMajor=Number(versionId.split('.')[0]); + return distro==='ubuntu' && Number.isFinite(versionMajor) && versionMajor>=24; + } catch { + return false; + } +} From a0eba49758006bf5f0b34f6039ab6ba0c19004e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 28 Sep 2026 06:07:09 +0000 Subject: [PATCH 3/5] Gate Ubuntu no-sandbox workaround by setuid sandbox availability Co-authored-by: highperformancecoder <3075825+highperformancecoder@users.noreply.github.com> --- .../src/app/app.sandbox.spec.ts | 14 +++++---- .../minsky-electron/src/app/linux-sandbox.ts | 29 +++++++++++++++++-- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts index 4d2418458..8b0ecd8dc 100644 --- a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts +++ b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts @@ -2,22 +2,26 @@ import { requiresNoSandboxOnLinux } from './linux-sandbox'; describe('requiresNoSandboxOnLinux', () => { it('returns true for Ubuntu 24.04', () => { - expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="24.04"\n')).toBe(true); + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="24.04"\n', false)).toBe(true); }); it('returns true for Ubuntu 26.04', () => { - expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="26.04"\n')).toBe(true); + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="26.04"\n', false)).toBe(true); + }); + + it('returns false for Ubuntu 24.04 when setuid sandbox is available', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="24.04"\n', true)).toBe(false); }); it('returns false for Ubuntu 22.04', () => { - expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="22.04"\n')).toBe(false); + expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="22.04"\n', false)).toBe(false); }); it('returns false for non-Ubuntu Linux', () => { - expect(requiresNoSandboxOnLinux('linux', 'ID=debian\nVERSION_ID="12"\n')).toBe(false); + expect(requiresNoSandboxOnLinux('linux', 'ID=debian\nVERSION_ID="12"\n', false)).toBe(false); }); it('returns false for non-Linux platforms', () => { - expect(requiresNoSandboxOnLinux('darwin', 'ID=ubuntu\nVERSION_ID="24.04"\n')).toBe(false); + expect(requiresNoSandboxOnLinux('darwin', 'ID=ubuntu\nVERSION_ID="24.04"\n', false)).toBe(false); }); }); diff --git a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts index 1f7f7f8d0..e53105cce 100644 --- a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts +++ b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts @@ -1,4 +1,5 @@ -import { existsSync, readFileSync } from 'fs'; +import { existsSync, readFileSync, statSync } from 'fs'; +import { dirname, join } from 'path'; function parseOsReleaseValue(osReleaseContent: string, key: string): string { const match=osReleaseContent.match(new RegExp(`^${key}=(.*)$`, 'm')); @@ -7,7 +8,8 @@ function parseOsReleaseValue(osReleaseContent: string, key: string): string { export function requiresNoSandboxOnLinux( platform=process.platform, - osReleaseContent?: string + osReleaseContent?: string, + hasUsableSandbox=hasUsableChromeSandbox() ): boolean { if (platform!=='linux') return false; try { @@ -20,8 +22,29 @@ export function requiresNoSandboxOnLinux( const distro=parseOsReleaseValue(osReleaseContent, 'ID'); const versionId=parseOsReleaseValue(osReleaseContent, 'VERSION_ID'); const versionMajor=Number(versionId.split('.')[0]); - return distro==='ubuntu' && Number.isFinite(versionMajor) && versionMajor>=24; + return distro==='ubuntu' && Number.isFinite(versionMajor) && versionMajor>=24 && !hasUsableSandbox; } catch { return false; } } + +function isSetuidRoot(path: string): boolean { + try { + const stat=statSync(path); + return stat.uid===0 && (stat.mode & 0o4000)!==0; + } catch { + return false; + } +} + +export function hasUsableChromeSandbox( + executablePath=process.execPath, + resourcesPath=process.resourcesPath +): boolean { + const candidates=[ + join(dirname(executablePath), 'chrome-sandbox'), + join(resourcesPath, 'chrome-sandbox'), + ]; + + return candidates.some(path => existsSync(path) && isSetuidRoot(path)); +} From 7f9daa70144f4b7e63ed93f4307acc2d177bbb65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 28 Sep 2026 06:08:37 +0000 Subject: [PATCH 4/5] Refine Linux sandbox gating and add normalization coverage Co-authored-by: highperformancecoder <3075825+highperformancecoder@users.noreply.github.com> --- gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts | 4 ++++ gui-js/apps/minsky-electron/src/app/linux-sandbox.ts | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts index 8b0ecd8dc..656a90d48 100644 --- a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts +++ b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts @@ -9,6 +9,10 @@ describe('requiresNoSandboxOnLinux', () => { expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="26.04"\n', false)).toBe(true); }); + it('normalizes quoted/mixed-case Ubuntu distro IDs', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID="Ubuntu"\nVERSION_ID="24.04"\n', false)).toBe(true); + }); + it('returns false for Ubuntu 24.04 when setuid sandbox is available', () => { expect(requiresNoSandboxOnLinux('linux', 'ID=ubuntu\nVERSION_ID="24.04"\n', true)).toBe(false); }); diff --git a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts index e53105cce..35044a9fd 100644 --- a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts +++ b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts @@ -9,7 +9,7 @@ function parseOsReleaseValue(osReleaseContent: string, key: string): string { export function requiresNoSandboxOnLinux( platform=process.platform, osReleaseContent?: string, - hasUsableSandbox=hasUsableChromeSandbox() + hasUsableSandbox?: boolean ): boolean { if (platform!=='linux') return false; try { @@ -22,6 +22,8 @@ export function requiresNoSandboxOnLinux( const distro=parseOsReleaseValue(osReleaseContent, 'ID'); const versionId=parseOsReleaseValue(osReleaseContent, 'VERSION_ID'); const versionMajor=Number(versionId.split('.')[0]); + if (hasUsableSandbox===undefined) + hasUsableSandbox=hasUsableChromeSandbox(); return distro==='ubuntu' && Number.isFinite(versionMajor) && versionMajor>=24 && !hasUsableSandbox; } catch { return false; From 6d1c444e4f113b317449def57bed7f95d10e313a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 28 Sep 2026 06:10:06 +0000 Subject: [PATCH 5/5] Support Ubuntu-like distro detection for sandbox workaround Co-authored-by: highperformancecoder <3075825+highperformancecoder@users.noreply.github.com> --- gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts | 4 ++++ gui-js/apps/minsky-electron/src/app/linux-sandbox.ts | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts index 656a90d48..698b4aa8a 100644 --- a/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts +++ b/gui-js/apps/minsky-electron/src/app/app.sandbox.spec.ts @@ -25,6 +25,10 @@ describe('requiresNoSandboxOnLinux', () => { expect(requiresNoSandboxOnLinux('linux', 'ID=debian\nVERSION_ID="12"\n', false)).toBe(false); }); + it('returns true for Ubuntu-like distro IDs on Linux 24+', () => { + expect(requiresNoSandboxOnLinux('linux', 'ID=linuxmint\nID_LIKE="ubuntu debian"\nVERSION_ID="24.04"\n', false)).toBe(true); + }); + it('returns false for non-Linux platforms', () => { expect(requiresNoSandboxOnLinux('darwin', 'ID=ubuntu\nVERSION_ID="24.04"\n', false)).toBe(false); }); diff --git a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts index 35044a9fd..819e27ba3 100644 --- a/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts +++ b/gui-js/apps/minsky-electron/src/app/linux-sandbox.ts @@ -20,11 +20,13 @@ export function requiresNoSandboxOnLinux( osReleaseContent=readFileSync(osRelease, 'utf8'); } const distro=parseOsReleaseValue(osReleaseContent, 'ID'); + const distroLike=parseOsReleaseValue(osReleaseContent, 'ID_LIKE'); const versionId=parseOsReleaseValue(osReleaseContent, 'VERSION_ID'); const versionMajor=Number(versionId.split('.')[0]); + const isUbuntuLike=distro==='ubuntu' || distroLike.split(/\s+/).includes('ubuntu'); if (hasUsableSandbox===undefined) hasUsableSandbox=hasUsableChromeSandbox(); - return distro==='ubuntu' && Number.isFinite(versionMajor) && versionMajor>=24 && !hasUsableSandbox; + return isUbuntuLike && Number.isFinite(versionMajor) && versionMajor>=24 && !hasUsableSandbox; } catch { return false; }