mirror of
https://github.com/garrytan/gstack.git
synced 2026-08-08 23:36:06 +02:00
fix(browse): GSTACK_CHROMIUM_NO_SANDBOX opt-out for Ubuntu/AppArmor (#1562)
Ubuntu/AppArmor configurations often block unprivileged Chromium sandboxing for headless agent sessions even for normal users — /qa hangs without --no-sandbox. The kernel policy denies the unprivileged user namespaces Chromium needs. Adds GSTACK_CHROMIUM_NO_SANDBOX=1 as an explicit user override that forces the sandbox off without changing the default for everyone else. Re-authored from PR #1562 onto v1.42.2.0's shouldEnableChromiumSandbox() helper — purely additive, preserves the headed-launch sandbox-on-by-default behavior that v1.42.2.0 shipped to kill the --no-sandbox yellow infobar. Three new regression tests cover: - linux + override=1 → false (the named use case) - darwin + override=1 → false (env wins on any platform) - override=0 → does NOT trigger (must be exactly "1") Original diff by @techcenter68 via #1562. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
7ea6b1dc89
commit
e7074b54d7
@@ -59,6 +59,13 @@ export function isCustomChromium(): boolean {
|
|||||||
*/
|
*/
|
||||||
export function shouldEnableChromiumSandbox(): boolean {
|
export function shouldEnableChromiumSandbox(): boolean {
|
||||||
if (process.platform === 'win32') return false;
|
if (process.platform === 'win32') return false;
|
||||||
|
// Explicit user override for Ubuntu/AppArmor and similar environments where
|
||||||
|
// unprivileged Chromium sandboxing is blocked even for normal users (the
|
||||||
|
// sandbox needs unprivileged user namespaces that the host policy denies,
|
||||||
|
// so /qa hangs without --no-sandbox). Setting GSTACK_CHROMIUM_NO_SANDBOX=1
|
||||||
|
// forces the sandbox off without changing the default for everyone else.
|
||||||
|
// See #1562.
|
||||||
|
if (process.env.GSTACK_CHROMIUM_NO_SANDBOX === '1') return false;
|
||||||
const isRoot = typeof process.getuid === 'function' && process.getuid() === 0;
|
const isRoot = typeof process.getuid === 'function' && process.getuid() === 0;
|
||||||
return !(process.env.CI || process.env.CONTAINER || isRoot);
|
return !(process.env.CI || process.env.CONTAINER || isRoot);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,20 @@ describe('shouldEnableChromiumSandbox', () => {
|
|||||||
const origPlatform = process.platform;
|
const origPlatform = process.platform;
|
||||||
const origCI = process.env.CI;
|
const origCI = process.env.CI;
|
||||||
const origContainer = process.env.CONTAINER;
|
const origContainer = process.env.CONTAINER;
|
||||||
|
const origNoSandbox = process.env.GSTACK_CHROMIUM_NO_SANDBOX;
|
||||||
const origGetuid = process.getuid;
|
const origGetuid = process.getuid;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
delete process.env.CI;
|
delete process.env.CI;
|
||||||
delete process.env.CONTAINER;
|
delete process.env.CONTAINER;
|
||||||
|
delete process.env.GSTACK_CHROMIUM_NO_SANDBOX;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
Object.defineProperty(process, 'platform', { value: origPlatform });
|
Object.defineProperty(process, 'platform', { value: origPlatform });
|
||||||
if (origCI === undefined) delete process.env.CI; else process.env.CI = origCI;
|
if (origCI === undefined) delete process.env.CI; else process.env.CI = origCI;
|
||||||
if (origContainer === undefined) delete process.env.CONTAINER; else process.env.CONTAINER = origContainer;
|
if (origContainer === undefined) delete process.env.CONTAINER; else process.env.CONTAINER = origContainer;
|
||||||
|
if (origNoSandbox === undefined) delete process.env.GSTACK_CHROMIUM_NO_SANDBOX; else process.env.GSTACK_CHROMIUM_NO_SANDBOX = origNoSandbox;
|
||||||
process.getuid = origGetuid;
|
process.getuid = origGetuid;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,6 +93,31 @@ describe('shouldEnableChromiumSandbox', () => {
|
|||||||
const { shouldEnableChromiumSandbox } = await import('../src/browser-manager');
|
const { shouldEnableChromiumSandbox } = await import('../src/browser-manager');
|
||||||
expect(shouldEnableChromiumSandbox()).toBe(false);
|
expect(shouldEnableChromiumSandbox()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// #1562 — Ubuntu/AppArmor opt-in override
|
||||||
|
it('linux + GSTACK_CHROMIUM_NO_SANDBOX=1 → false (Ubuntu/AppArmor opt-out)', async () => {
|
||||||
|
setPlatform('linux');
|
||||||
|
process.env.GSTACK_CHROMIUM_NO_SANDBOX = '1';
|
||||||
|
process.getuid = (() => 1000) as typeof process.getuid;
|
||||||
|
const { shouldEnableChromiumSandbox } = await import('../src/browser-manager');
|
||||||
|
expect(shouldEnableChromiumSandbox()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('darwin + GSTACK_CHROMIUM_NO_SANDBOX=1 → false (env override wins on any platform)', async () => {
|
||||||
|
setPlatform('darwin');
|
||||||
|
process.env.GSTACK_CHROMIUM_NO_SANDBOX = '1';
|
||||||
|
process.getuid = (() => 501) as typeof process.getuid;
|
||||||
|
const { shouldEnableChromiumSandbox } = await import('../src/browser-manager');
|
||||||
|
expect(shouldEnableChromiumSandbox()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('GSTACK_CHROMIUM_NO_SANDBOX=0 → does NOT trigger override (must be exactly "1")', async () => {
|
||||||
|
setPlatform('linux');
|
||||||
|
process.env.GSTACK_CHROMIUM_NO_SANDBOX = '0';
|
||||||
|
process.getuid = (() => 1000) as typeof process.getuid;
|
||||||
|
const { shouldEnableChromiumSandbox } = await import('../src/browser-manager');
|
||||||
|
expect(shouldEnableChromiumSandbox()).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── resolveDisconnectCause ──────────────────────────────────────
|
// ─── resolveDisconnectCause ──────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user