|
1 | 1 | import { describe, it, expect, vi } from 'vitest'; |
2 | | -import { generateBaseConfig, writeBaseConfig, MAX_CONFIG_BACKUPS } from './config-writer'; |
| 2 | +import { |
| 3 | + backupConfigFile, |
| 4 | + generateBaseConfig, |
| 5 | + writeBaseConfig, |
| 6 | + MAX_CONFIG_BACKUPS, |
| 7 | +} from './config-writer'; |
3 | 8 |
|
4 | 9 | /** Minimal config that `openclaw onboard` would produce. */ |
5 | 10 | const ONBOARD_CONFIG = JSON.stringify({ |
@@ -33,6 +38,7 @@ function fakeDeps(existingConfig?: string) { |
33 | 38 | }), |
34 | 39 | copyFileSync: vi.fn((src: string, dest: string) => { |
35 | 40 | copied.push({ src, dest }); |
| 41 | + dirEntries = [...dirEntries, dest.split('/').pop() ?? dest]; |
36 | 42 | }), |
37 | 43 | readdirSync: vi.fn(() => dirEntries), |
38 | 44 | unlinkSync: vi.fn((filePath: string) => { |
@@ -320,6 +326,80 @@ describe('generateBaseConfig', () => { |
320 | 326 |
|
321 | 327 | expect(config.gateway.auth).toBeUndefined(); |
322 | 328 | }); |
| 329 | + |
| 330 | + it('does not set allowInsecureAuth when AUTO_APPROVE_DEVICES is not true', () => { |
| 331 | + const { deps } = fakeDeps(); |
| 332 | + const env = { ...minimalEnv() }; |
| 333 | + delete env.AUTO_APPROVE_DEVICES; |
| 334 | + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); |
| 335 | + |
| 336 | + expect(config.gateway.controlUi?.allowInsecureAuth).toBeUndefined(); |
| 337 | + }); |
| 338 | + |
| 339 | + it('does not set allowInsecureAuth when AUTO_APPROVE_DEVICES is false', () => { |
| 340 | + const { deps } = fakeDeps(); |
| 341 | + const env = { ...minimalEnv(), AUTO_APPROVE_DEVICES: 'false' }; |
| 342 | + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); |
| 343 | + |
| 344 | + expect(config.gateway.controlUi?.allowInsecureAuth).toBeUndefined(); |
| 345 | + }); |
| 346 | + |
| 347 | + it('configures Telegram allowFrom from explicit comma-separated list', () => { |
| 348 | + const { deps } = fakeDeps(); |
| 349 | + const env = { |
| 350 | + ...minimalEnv(), |
| 351 | + TELEGRAM_BOT_TOKEN: 'tg-token', |
| 352 | + TELEGRAM_DM_ALLOW_FROM: 'user1,user2', |
| 353 | + }; |
| 354 | + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); |
| 355 | + |
| 356 | + expect(config.channels.telegram.allowFrom).toEqual(['user1', 'user2']); |
| 357 | + expect(config.channels.telegram.dmPolicy).toBe('pairing'); |
| 358 | + }); |
| 359 | +}); |
| 360 | + |
| 361 | +describe('backupConfigFile', () => { |
| 362 | + it('backs up existing config with timestamp', () => { |
| 363 | + const existing = JSON.stringify({ old: true }); |
| 364 | + const { deps, copied } = fakeDeps(existing); |
| 365 | + |
| 366 | + backupConfigFile('/tmp/openclaw.json', deps); |
| 367 | + |
| 368 | + expect(copied).toHaveLength(1); |
| 369 | + expect(copied[0].src).toBe('/tmp/openclaw.json'); |
| 370 | + expect(copied[0].dest).toMatch(/\/tmp\/openclaw\.json\.bak\.\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-/); |
| 371 | + }); |
| 372 | + |
| 373 | + it('prunes old backups beyond MAX_CONFIG_BACKUPS', () => { |
| 374 | + const existing = JSON.stringify({ old: true }); |
| 375 | + const harness = fakeDeps(existing); |
| 376 | + harness.setDirEntries([ |
| 377 | + 'openclaw.json.bak.2026-02-20T10-00-00.000Z', |
| 378 | + 'openclaw.json.bak.2026-02-21T10-00-00.000Z', |
| 379 | + 'openclaw.json.bak.2026-02-22T10-00-00.000Z', |
| 380 | + 'openclaw.json.bak.2026-02-23T10-00-00.000Z', |
| 381 | + 'openclaw.json.bak.2026-02-24T10-00-00.000Z', |
| 382 | + 'openclaw.json.bak.2026-02-25T10-00-00.000Z', |
| 383 | + 'openclaw.json.bak.2026-02-26T10-00-00.000Z', |
| 384 | + ]); |
| 385 | + |
| 386 | + backupConfigFile('/tmp/openclaw.json', harness.deps); |
| 387 | + |
| 388 | + expect(harness.unlinked).toHaveLength(8 - MAX_CONFIG_BACKUPS); |
| 389 | + expect(harness.unlinked[0]).toBe('/tmp/openclaw.json.bak.2026-02-20T10-00-00.000Z'); |
| 390 | + expect(harness.unlinked[1]).toBe('/tmp/openclaw.json.bak.2026-02-21T10-00-00.000Z'); |
| 391 | + }); |
| 392 | + |
| 393 | + it('continues if backup pruning fails', () => { |
| 394 | + const existing = JSON.stringify({ old: true }); |
| 395 | + const harness = fakeDeps(existing); |
| 396 | + harness.deps.readdirSync.mockImplementation(() => { |
| 397 | + throw new Error('permission denied'); |
| 398 | + }); |
| 399 | + |
| 400 | + expect(() => backupConfigFile('/tmp/openclaw.json', harness.deps)).not.toThrow(); |
| 401 | + expect(harness.copied).toHaveLength(1); |
| 402 | + }); |
323 | 403 | }); |
324 | 404 |
|
325 | 405 | describe('writeBaseConfig', () => { |
@@ -413,7 +493,7 @@ describe('writeBaseConfig', () => { |
413 | 493 |
|
414 | 494 | writeBaseConfig(minimalEnv(), '/tmp/openclaw.json', harness.deps); |
415 | 495 |
|
416 | | - expect(harness.unlinked).toHaveLength(7 - MAX_CONFIG_BACKUPS); |
| 496 | + expect(harness.unlinked).toHaveLength(8 - MAX_CONFIG_BACKUPS); |
417 | 497 | expect(harness.unlinked[0]).toBe('/tmp/openclaw.json.bak.2026-02-20T10-00-00.000Z'); |
418 | 498 | expect(harness.unlinked[1]).toBe('/tmp/openclaw.json.bak.2026-02-21T10-00-00.000Z'); |
419 | 499 | }); |
|
0 commit comments