e2e-web-server.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import { randomBytes, scryptSync } from 'node:crypto'
  2. import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
  3. const testHome = '/tmp/hermes-yaoyao-e2e-home'
  4. const testUserID = '11111111-1111-4111-8111-111111111112'
  5. rmSync(testHome, { recursive: true, force: true })
  6. mkdirSync(testHome, { recursive: true, mode: 0o700 })
  7. // The browser fixture exercises the ownership registry, not the mutable
  8. // upstream `source` field. Seed only the sessions that were explicitly
  9. // created by this local Web user; session-history-only deliberately remains
  10. // unowned even though fake Hermes labels it source=web.
  11. const salt = randomBytes(16)
  12. const now = Date.now()
  13. writeFileSync(`${testHome}/users.json`, JSON.stringify({
  14. version: 1,
  15. users: [{
  16. id: testUserID,
  17. username: 'admin',
  18. normalizedUsername: 'admin',
  19. role: 'admin',
  20. enabled: true,
  21. mustChangePassword: false,
  22. salt: salt.toString('base64'),
  23. passwordHash: scryptSync('e2e-password', salt, 32, {
  24. N: 2 ** 14,
  25. r: 8,
  26. p: 1,
  27. maxmem: 64 * 1024 * 1024,
  28. }).toString('base64'),
  29. authVersion: 1,
  30. createdAt: now,
  31. updatedAt: now,
  32. }],
  33. }), { mode: 0o600 })
  34. const ownedSessions = [
  35. ['session-demo', 'yaoyao'],
  36. ['session-second', 'yaoyao'],
  37. ['session-yaoer', 'yaoer'],
  38. ['session-media', 'yaoer'],
  39. ['session-user-media', 'yaoer'],
  40. ...Array.from({ length: 101 }, (_, index) => [`session-page-${index + 1}`, 'yaoyao']),
  41. ]
  42. const { ChatCacheStore } = await import('../../dist-server/server/chatCache.js')
  43. // General media fixtures intentionally span several server directories.
  44. // Permission-specific QA leaves the production cwd-only default intact.
  45. if (process.env.YAOYAO_FILE_ACCESS_TEST_MODE !== 'cwd') {
  46. const { saveFileAccess } = await import('../../dist-server/server/fileAccess.js')
  47. saveFileAccess(testHome, { mode: 'all', folders: [] })
  48. }
  49. const registry = new ChatCacheStore(testHome, testUserID)
  50. for (const [sessionID, profile] of ownedSessions) {
  51. registry.recordCommand(testUserID, profile, sessionID, 'session.create', {
  52. profile,
  53. source: 'web',
  54. })
  55. }
  56. // These are existing Hermes histories, not empty sessions created by this build.
  57. // Exercise the durable background import, never a blocking list fallback.
  58. registry.db.exec('UPDATE chat_sessions SET metadata_complete=0,complete=0,message_total=NULL')
  59. registry.db.exec('INSERT OR IGNORE INTO chat_recovery_jobs(owner,profile,session_id) SELECT owner,profile,session_id FROM chat_sessions WHERE owned_at IS NOT NULL')
  60. registry.close()
  61. Object.assign(process.env, {
  62. NODE_ENV: 'production',
  63. HERMES_YAOYAO_HOME: testHome,
  64. HERMES_YAOYAO_HOST: '127.0.0.1',
  65. HERMES_YAOYAO_PORT: '18801',
  66. HERMES_YAOYAO_UPSTREAM: 'http://127.0.0.1:19119',
  67. HERMES_YAOYAO_UPSTREAM_USERNAME: 'test',
  68. HERMES_YAOYAO_UPSTREAM_PASSWORD: 'test',
  69. })
  70. if (process.env.FAKE_HERMES_LOCAL_AUTH === '1') {
  71. delete process.env.HERMES_YAOYAO_UPSTREAM_USERNAME
  72. delete process.env.HERMES_YAOYAO_UPSTREAM_PASSWORD
  73. delete process.env.HERMES_YAOYAO_UPSTREAM_PASSWORD_FILE
  74. }
  75. await import('../../dist-server/server/index.js')