| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- // @vitest-environment node
- import {afterEach,expect,it,vi} from 'vitest'
- import {EventEmitter} from 'node:events'
- import {mkdtemp,readFile,writeFile,rm} from 'node:fs/promises'
- import {randomUUID,randomBytes,createCipheriv,createDecipheriv} from 'node:crypto'
- import {tmpdir} from 'node:os'
- import {join} from 'node:path'
- import {parseRunnerConfiguration} from '../../src/runner/config.js'
- import {RunnerAgent} from '../../src/runner/agent.js'
- import type {RunnerConfiguration} from '../../src/shared/runner.js'
- import {DesktopRunnerManager} from '../../desktop/runner-manager.mjs'
- const browserConstructed=vi.hoisted(()=>vi.fn())
- vi.mock('../../src/runner/managedBrowser.js',()=>({RunnerBrowser:class {
- available=false
- constructor(config:unknown){browserConstructed(config)}
- async disconnect(){}async shutdown(){}async sweep(){}
- }}))
- const base=()=>({protocol:1 as const,runnerId:randomUUID(),token:randomBytes(32).toString('base64url'),serverURL:'https://fixture.invalid',hermesURL:'http://127.0.0.1:9119',allowedProfiles:['default'],artifactRoots:[]})
- afterEach(()=>vi.clearAllMocks())
- it.each([undefined,{}, {enabled:false,maxSessions:2,idleTimeoutMs:120000}])('revalidates an old encrypted desktop configuration on restart and import (%j)',async browser=>{
- const home=await mkdtemp(join(tmpdir(),'yaoyao-browser-config-upgrade-')),key=randomBytes(32),children:any[]=[]
- const encrypt=(value:string)=>{const iv=randomBytes(12),cipher=createCipheriv('aes-256-gcm',key,iv),bytes=Buffer.concat([cipher.update(value),cipher.final()]);return Buffer.concat([iv,cipher.getAuthTag(),bytes])}
- const decrypt=(bytes:Buffer)=>{const cipher=createDecipheriv('aes-256-gcm',key,bytes.subarray(0,12));cipher.setAuthTag(bytes.subarray(12,28));return Buffer.concat([cipher.update(bytes.subarray(28)),cipher.final()]).toString()}
- const manager=new DesktopRunnerManager({home,encrypt,decrypt,validate:parseRunnerConfiguration,fork:()=>{
- const child=Object.assign(new EventEmitter(),{messages:[] as any[],postMessage(value:any){this.messages.push(value);if(value.type==='shutdown')queueMicrotask(()=>this.emit('exit',0))},kill(){queueMicrotask(()=>this.emit('exit',0));return true}})
- children.push(child);queueMicrotask(()=>child.emit('spawn'));return child
- }})
- const config={...base(),...(browser?{browser}:{})},encrypted=encrypt(JSON.stringify(config)),expected=browser?.enabled===false?browser:{enabled:true}
- try{
- // Existing bytes are the pre-upgrade settings; start must not rewrite them.
- await writeFile(manager.path,encrypted,{mode:0o600});await manager.start()
- expect(children[0].messages.find((item:any)=>item.type==='configure').config.browser).toEqual(expected)
- expect(await readFile(manager.path)).toEqual(encrypted)
- await manager.stop();await manager.start()
- expect(children[1].messages.find((item:any)=>item.type==='configure').config.browser).toEqual(expected)
- const file=join(home,'runner.json');await writeFile(file,JSON.stringify(config),{mode:0o600})
- await manager.importFile(file)
- expect(children[2].messages.find((item:any)=>item.type==='configure').config.browser).toEqual(expected)
- expect((await readFile(manager.path)).includes(config.token)).toBe(false)
- }finally{await manager.stop();await rm(home,{recursive:true,force:true})}
- })
- it.each([undefined,{}, {enabled:false}])('advertises setup for direct/embedded old configurations unless explicitly disabled (%j)',async browser=>{
- const home=await mkdtemp(join(tmpdir(),'yaoyao-browser-agent-upgrade-'))
- const fetchImpl=vi.fn(async()=>Response.json({commands:[],epoch:randomUUID()}))
- const runner=new RunnerAgent({...base(),...(browser?{browser}:{})} as RunnerConfiguration,home,fetchImpl as typeof fetch)
- try{
- await (runner as any).api('poll')
- const headers=new Headers(fetchImpl.mock.calls[0]![1]?.headers)
- const features=headers.get('x-runner-features')!.split(',')
- expect(features.includes('managed-browser-setup-v1')).toBe(browser?.enabled!==false)
- expect(features.includes('managed-browser-disabled-v1')).toBe(browser?.enabled===false)
- expect(features).not.toContain('managed-browser-v1')
- expect(features).not.toContain('local-vm-v1')
- if(browser?.enabled===false)expect(browserConstructed).not.toHaveBeenCalled()
- else expect(browserConstructed).toHaveBeenCalledWith({enabled:true})
- }finally{const stop=new AbortController();stop.abort();await runner.run(stop.signal);await rm(home,{recursive:true,force:true})}
- })
|