import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; let tempHome: string; vi.mock('os', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, homedir: () => tempHome, }; }); import { getAutoStateFilePath, isValidSessionName, getSessionsDir, safeHeaderMerge, listStateFiles, cleanupExpiredStates, } from './state-utils.js'; describe('state-utils', () => { beforeEach(() => { tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-browser-test-')); }); afterEach(() => { fs.rmSync(tempHome, { recursive: true, force: true }); }); describe('isValidSessionName', () => { it('should accept alphanumeric names', () => { expect(isValidSessionName('twitter')).toBe(true); expect(isValidSessionName('Twitter123')).toBe(true); expect(isValidSessionName('123')).toBe(true); expect(isValidSessionName('ABC')).toBe(true); }); it('should accept names with hyphens', () => { expect(isValidSessionName('my-session')).toBe(true); expect(isValidSessionName('twitter-prod')).toBe(true); expect(isValidSessionName('a-b-c-d')).toBe(true); }); it('should accept names with underscores', () => { expect(isValidSessionName('my_session')).toBe(true); expect(isValidSessionName('twitter_prod')).toBe(true); expect(isValidSessionName('a_b_c_d')).toBe(true); }); it('should accept mixed valid characters', () => { expect(isValidSessionName('my-session_123')).toBe(true); expect(isValidSessionName('Twitter_Prod-v2')).toBe(true); }); it('should reject empty string', () => { expect(isValidSessionName('')).toBe(false); }); it('should reject path traversal attempts', () => { expect(isValidSessionName('../../../etc/passwd')).toBe(false); expect(isValidSessionName('..\\..\\windows\\system32')).toBe(false); expect(isValidSessionName('../parent')).toBe(false); expect(isValidSessionName('./current')).toBe(false); }); it('should reject names with slashes', () => { expect(isValidSessionName('path/to/file')).toBe(false); expect(isValidSessionName('path\\to\\file')).toBe(false); expect(isValidSessionName('/absolute/path')).toBe(false); }); it('should reject names with spaces', () => { expect(isValidSessionName('my session')).toBe(false); expect(isValidSessionName(' leading')).toBe(false); expect(isValidSessionName('trailing ')).toBe(false); }); it('should reject names with special characters', () => { expect(isValidSessionName('session@user')).toBe(false); expect(isValidSessionName('session#1')).toBe(false); expect(isValidSessionName('session$var')).toBe(false); expect(isValidSessionName('session%20')).toBe(false); expect(isValidSessionName('session:name')).toBe(false); expect(isValidSessionName('session;drop')).toBe(false); expect(isValidSessionName("session'sql")).toBe(false); expect(isValidSessionName('session"quote')).toBe(false); expect(isValidSessionName('session