computerAuth.live.test.ts 4.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. // @vitest-environment node
  2. import {expect,it} from 'vitest'
  3. import {mkdtemp,readdir,readFile,rm} from 'node:fs/promises'
  4. import {tmpdir} from 'node:os'
  5. import {join} from 'node:path'
  6. import {randomUUID} from 'node:crypto'
  7. import {ContainerComputerProvider,type ComputerSpecification} from '../../src/runner/computers/container'
  8. import {ComputerMaintenance} from '../../src/runner/computers/maintenance'
  9. it.skipIf(!process.env.YAOYAO_COMPUTER_IMAGE)('migrates a legacy home and keeps real browser and encrypted application authorization through rebuild and restore',async()=>{
  10. const home=await mkdtemp(join(tmpdir(),'yaoyao-auth-live-'))
  11. const provider=new ContainerComputerProvider('docker',randomUUID(),home)
  12. const spec:ComputerSpecification={id:randomUUID(),ownerKey:randomUUID(),imageId:process.env.YAOYAO_COMPUTER_IMAGE!,network:process.env.YAOYAO_COMPUTER_NETWORK==='managed-proxy'?'managed-proxy':'none'}
  13. const script=await readFile(new URL('../fixtures/computer_auth.mjs',import.meta.url),'utf8')
  14. const execute=(argv:string[],user:'cua'|'root'='cua')=>provider.execute(spec,argv,{authorize:()=>{},user,timeout:60000}).catch(error=>{throw new Error(`${argv[0]} ${argv.at(-1)}: ${error.stderr??error.message}`)})
  15. const maintenance=new ComputerMaintenance({status:()=>[{environmentId:spec.id,status:'free'}]} as any,provider,home)
  16. let derivedImage:string|undefined
  17. try{
  18. // Exercise the real upgrade path from the old workspace-only container.
  19. const workspace=await (provider as any).workspace(provider.validateSpecification(spec))
  20. if(spec.network==='managed-proxy')await (provider as any).ensureNetwork(provider.validateSpecification(spec),()=>{})
  21. const created=await provider.run('docker',(provider as any).args(provider.validateSpecification(spec),workspace))
  22. const legacyId=created.stdout.trim();await provider.run('docker',['start',legacyId])
  23. expect(JSON.parse((await execute(['node','--input-type=module','-e',script,'login'])).stdout)).toEqual({browser:true,encryptedApplicationToken:true})
  24. await execute(['sh','-c','mkdir -p /root/.config; printf root-fixture > /root/.config/authorization'],'root')
  25. const identity=(await execute(['cat','/var/lib/dbus/machine-id'])).stdout
  26. // The updater uses a fresh provider without a cached gateway identity.
  27. const migration=new ContainerComputerProvider('docker',provider.runnerId,home)
  28. expect(await migration.preserveUserData(spec)).toBe(true)
  29. await provider.remove(spec)
  30. const migrated=await provider.ensure(spec,()=>{})
  31. expect(migrated.containerId).not.toBe(legacyId)
  32. expect((await execute(['cat','/etc/machine-id'])).stdout).toBe(identity)
  33. expect((await execute(['cat','/root/.config/authorization'],'root')).stdout).toBe('root-fixture')
  34. expect(JSON.parse((await execute(['node','--input-type=module','-e',script,'check'])).stdout).browser).toBe(true)
  35. await maintenance.rebuild(spec);await provider.ensure(spec,()=>{})
  36. expect(JSON.parse((await execute(['node','--input-type=module','-e',script,'check'])).stdout).encryptedApplicationToken).toBe(true)
  37. await provider.stop(spec)
  38. derivedImage=(await provider.run('docker',['commit',(await provider.inspect(spec))!.containerId],{timeout:60000})).stdout.trim()
  39. await provider.remove(spec);spec.imageId=derivedImage
  40. await provider.ensure(spec,()=>{})
  41. expect(JSON.parse((await execute(['node','--input-type=module','-e',script,'check'])).stdout).browser).toBe(true)
  42. expect(await readdir(join(home,'computer-backups',spec.id))).toHaveLength(1)
  43. await maintenance.backup(spec,join(home,'snapshot'))
  44. await provider.ensure(spec,()=>{})
  45. await execute(['sh','-c','rm -rf ~/.config/yaoyao-auth-fixture ~/.local/share/keyrings/yaoyao-auth-fixture ~/.config/yaoyao-auth-browser'])
  46. await maintenance.restore(spec,join(home,'snapshot'))
  47. await provider.ensure(spec,()=>{})
  48. expect(JSON.parse((await execute(['node','--input-type=module','-e',script,'check'])).stdout).browser).toBe(true)
  49. expect((await execute(['cat','/etc/machine-id'])).stdout).toBe(identity)
  50. }finally{await provider.remove(spec);if(derivedImage)await provider.run('docker',['image','rm',derivedImage]);await rm(home,{recursive:true,force:true})}
  51. },180000)