runnerConfig.test.ts 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. // @vitest-environment node
  2. import {expect,it} from 'vitest'
  3. import {randomUUID} from 'node:crypto'
  4. import {homedir} from 'node:os'
  5. import {join} from 'node:path'
  6. import {parseRunnerConfiguration} from '../../src/runner/config'
  7. const config={protocol:1,runnerId:randomUUID(),token:'secret-fixture-'.repeat(3),serverURL:'https://example.invalid',hermesURL:'http://127.0.0.1:9119',allowedProfiles:['default'],artifactRoots:[]}
  8. it.each([
  9. {serverURL:'http://example.invalid'},
  10. {serverURL:'https://user:password@example.invalid'},
  11. {serverURL:'https://example.invalid/path'},
  12. {hermesURL:'http://host.docker.internal:9119'},
  13. {hermesURL:'http://user:password@127.0.0.1:9119'},
  14. {artifactRoots:['relative/path']},
  15. {allowedProfiles:['../default']},
  16. {protocol:2},
  17. {command:'/bin/sh'},
  18. ])('rejects invalid or expanded node configuration without echoing credentials (%j)',patch=>{
  19. expect(()=>parseRunnerConfiguration({...config,...patch})).toThrow()
  20. try{parseRunnerConfiguration({...config,...patch})}catch(error){expect(String(error)).not.toContain(config.token);expect(String(error)).not.toContain('password')}
  21. })
  22. it('accepts explicit LAN opt-in and keeps service credentials in the private configuration',()=>{
  23. expect(parseRunnerConfiguration({...config,serverURL:'http://192.168.1.2:15300',allowInsecureLan:true,hermesCredentials:{username:'fixture',password:'private'}})).toMatchObject({allowInsecureLan:true,hermesCredentials:{username:'fixture',password:'private'}})
  24. })
  25. it('keeps existing computer configurations offline unless public access is explicitly enabled',()=>{
  26. const computers={runtime:'docker',imageId:'sha256:'+ 'a'.repeat(64),python:'/fixture/python',hermesSource:'/fixture/source',hermesHome:'/fixture/home'}
  27. expect(parseRunnerConfiguration({...config,computers}).computers?.network).toBe('none')
  28. expect(parseRunnerConfiguration({...config,computers:{...computers,network:'public-proxy'}}).computers?.network).toBe('public-proxy')
  29. expect(()=>parseRunnerConfiguration({...config,computers:{...computers,network:'host'}})).toThrow()
  30. })
  31. it('resolves optional Hermes paths on the execution host while preserving explicit installation paths',()=>{
  32. const computers={runtime:'docker',imageId:'sha256:'+'0'.repeat(64)}
  33. expect(parseRunnerConfiguration({...config,computers}).computers).toMatchObject({hermesHome:join(homedir(),'.hermes'),hermesSource:join(homedir(),'.hermes','hermes-agent'),python:join(homedir(),'.hermes','hermes-agent','venv','bin','python')})
  34. expect(parseRunnerConfiguration({...config,computers:{...computers,hermesHome:'/custom/hermes',hermesSource:'/custom/source',python:''}}).computers?.python).toBe('/custom/source/venv/bin/python')
  35. expect(()=>parseRunnerConfiguration({...config,computers:{...computers,hermesHome:'relative'}})).toThrow()
  36. })
  37. it('rejects the retired satellite runner',()=>{
  38. expect(()=>parseRunnerConfiguration({...config,satellite:true,hermesURL:'https://hermes.example',allowInsecureLan:true})).toThrow('卫星执行节点已停用')
  39. })
  40. it('upgrades omitted browser settings while preserving explicit opt-out and VM isolation',()=>{
  41. expect(parseRunnerConfiguration(config).browser).toEqual({enabled:true})
  42. expect(parseRunnerConfiguration({...config,browser:{}}).browser).toEqual({enabled:true})
  43. const browser={enabled:false,maxSessions:2,idleTimeoutMs:120000}
  44. const computers={runtime:'docker',imageId:'sha256:'+'a'.repeat(64),network:'none',python:'/fixture/python',hermesSource:'/fixture/source',hermesHome:'/fixture/home'}
  45. const disabled=parseRunnerConfiguration({...config,browser,computers})
  46. expect(disabled.browser).toEqual(browser);expect(disabled.computers).toEqual(computers)
  47. expect(parseRunnerConfiguration({...config,computers}).computers).toEqual(computers)
  48. for(const invalid of [{enabled:'false'},{enabled:null},{enabled:true,command:'install'}])expect(()=>parseRunnerConfiguration({...config,browser:invalid})).toThrow()
  49. })