diff --git a/server/modules/browser-use/browser-use.settings.ts b/server/modules/browser-use/browser-use.settings.ts index 3aaeeb05..c4bead86 100644 --- a/server/modules/browser-use/browser-use.settings.ts +++ b/server/modules/browser-use/browser-use.settings.ts @@ -19,7 +19,8 @@ export const DEFAULT_BROWSER_USE_SETTINGS: BrowserUseSettings = { browserBackend: IS_PLATFORM ? 'camoufox-vnc' : 'playwright', }; -export const PROFILE_ROOT = path.join(os.homedir(), '.cloudcli', 'browser-use', 'profiles'); +export const PROFILE_ROOT = process.env.CLOUDCLI_BROWSER_USE_PROFILE_ROOT + || path.join(os.homedir(), '.cloudcli', 'browser-use', 'profiles'); export function normalizeBrowserBackend(value: unknown): BrowserUseBackend { return value === 'playwright' || value === 'camoufox-vnc' @@ -27,12 +28,24 @@ export function normalizeBrowserBackend(value: unknown): BrowserUseBackend { : DEFAULT_BROWSER_USE_SETTINGS.browserBackend; } +function trimEdgeDashes(value: string): string { + let start = 0; + let end = value.length; + while (start < end && value[start] === '-') { + start += 1; + } + while (end > start && value[end - 1] === '-') { + end -= 1; + } + return value.slice(start, end); +} + export function normalizeProfileName(profileName?: string | null): string | null { - const normalized = String(profileName || '') + const sanitized = trimEdgeDashes(String(profileName || '') .trim() .toLowerCase() - .replace(/[^a-z0-9._-]+/g, '-') - .replace(/^-+|-+$/g, '') + .replace(/[^a-z0-9._-]+/g, '-')); + const normalized = sanitized .slice(0, MAX_PROFILE_NAME_LENGTH) .replace(/^-+|-+$/g, ''); if (!normalized) { diff --git a/server/modules/browser-use/tests/browser-use.settings.test.ts b/server/modules/browser-use/tests/browser-use.settings.test.ts index a814e1d3..1e04a6c5 100644 --- a/server/modules/browser-use/tests/browser-use.settings.test.ts +++ b/server/modules/browser-use/tests/browser-use.settings.test.ts @@ -1,17 +1,33 @@ import assert from 'node:assert/strict'; import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; import test from 'node:test'; -import { +const originalProfileRoot = process.env.CLOUDCLI_BROWSER_USE_PROFILE_ROOT; +const testProfileRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'browser-use-profiles-')); +process.env.CLOUDCLI_BROWSER_USE_PROFILE_ROOT = testProfileRoot; + +const { getProfilePath, normalizeDefaultProfileName, normalizeProfileName, PROFILE_ROOT, resolveSessionProfileName, -} from '@/modules/browser-use/browser-use.settings.js'; +} = await import('@/modules/browser-use/browser-use.settings.js'); + +test.after(() => { + if (originalProfileRoot === undefined) { + delete process.env.CLOUDCLI_BROWSER_USE_PROFILE_ROOT; + } else { + process.env.CLOUDCLI_BROWSER_USE_PROFILE_ROOT = originalProfileRoot; + } + fs.rmSync(testProfileRoot, { recursive: true, force: true }); +}); test('browser profile names are canonicalized before storage and path resolution', () => { assert.equal(normalizeProfileName(' Work Profile!! '), 'work-profile'); + assert.equal(normalizeProfileName(`${'-'.repeat(100)}Work Profile`), 'work-profile'); assert.equal(normalizeDefaultProfileName(' Work Profile!! '), 'work-profile'); assert.equal( getProfilePath(' Work Profile!! '),