From 8b9ea624efe0bb8d413e2a16ff3e8792c7423a8f Mon Sep 17 00:00:00 2001 From: ethernet Date: Tue, 22 Sep 2026 13:03:06 -0400 Subject: [PATCH] fix(e2e): isolate update window from Chromium state --- tests-js/scripts/launch-from-spec.test.ts | 4 +++- tests/install/e2e-assets/smoke-env.mjs | 19 +++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tests-js/scripts/launch-from-spec.test.ts b/tests-js/scripts/launch-from-spec.test.ts index 8cac229128..667bc839e4 100644 --- a/tests-js/scripts/launch-from-spec.test.ts +++ b/tests-js/scripts/launch-from-spec.test.ts @@ -13,11 +13,12 @@ test('the update window pins its isolated route before Electron requests the sin )).toEqual(['--user-data-dir=/isolated/route', '--no-sandbox', '--inspect=0']) }) -test('the update window clones userData without inheriting another Electron singleton', (): void => { +test('the update window carries Hermes connection state without cloning Chromium state', (): void => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'update-window-userdata-')) const userData = path.join(root, 'electron-user-data') fs.mkdirSync(userData) fs.writeFileSync(path.join(userData, 'connections.json'), '{"primary":"local"}\n') + fs.writeFileSync(path.join(userData, 'Local State'), 'chromium-owned\n') for (const name of ['SingletonLock', 'SingletonSocket', 'SingletonCookie']) { fs.symlinkSync(path.join(root, `${name}-target`), path.join(userData, name)) @@ -37,6 +38,7 @@ test('the update window clones userData without inheriting another Electron sing expect(captured.HERMES_DESKTOP_USER_DATA_DIR).toBe(userData) expect(isolated.HERMES_HOME).toBe(captured.HERMES_HOME) expect(fs.readFileSync(path.join(isolatedUserData, 'connections.json'), 'utf8')).toBe('{"primary":"local"}\n') + expect(fs.existsSync(path.join(isolatedUserData, 'Local State'))).toBe(false) for (const name of ['SingletonLock', 'SingletonSocket', 'SingletonCookie']) { expect(() => fs.lstatSync(path.join(isolatedUserData, name))).toThrow() diff --git a/tests/install/e2e-assets/smoke-env.mjs b/tests/install/e2e-assets/smoke-env.mjs index 6fd4e6222a..564ae4eeaa 100644 --- a/tests/install/e2e-assets/smoke-env.mjs +++ b/tests/install/e2e-assets/smoke-env.mjs @@ -53,12 +53,14 @@ export function smokeEnvironment(inherited, home, userData) { }; } -const SINGLETON_FILES = new Set(['SingletonLock', 'SingletonSocket', 'SingletonCookie']); +const UPDATE_WINDOW_STATE = ['connection.json', 'connections.json']; /** * Give the independently driven update window its own Electron instance route. - * The cloned state keeps the real connection and desktop preferences, while - * HERMES_HOME remains shared so the app updates the actual installed runtime. + * Copy only Hermes-owned connection contracts. Cloning Chromium's profile + * carries browser locks and process state from the prior app into a supposedly + * isolated launch. HERMES_HOME remains shared so the app updates the actual + * installed runtime. * * @template {Record} T * @param {T & {HERMES_DESKTOP_USER_DATA_DIR: string}} env @@ -67,13 +69,10 @@ const SINGLETON_FILES = new Set(['SingletonLock', 'SingletonSocket', 'SingletonC export function isolateUpdateWindowEnvironment(env) { const source = env.HERMES_DESKTOP_USER_DATA_DIR; const isolated = fs.mkdtempSync(path.join(path.dirname(source), `${path.basename(source)}-app-update-`)); - fs.cpSync(source, isolated, { - recursive: true, - filter: (candidate) => { - const relative = path.relative(source, candidate); - return relative === '' || relative.includes(path.sep) || !SINGLETON_FILES.has(relative); - }, - }); + for (const filename of UPDATE_WINDOW_STATE) { + const from = path.join(source, filename); + if (fs.existsSync(from)) fs.copyFileSync(from, path.join(isolated, filename)); + } return { ...env, HERMES_DESKTOP_USER_DATA_DIR: isolated }; }