diff --git a/src/infra/device-identity.state-dir.test.ts b/src/infra/device-identity.state-dir.test.ts index 785fa343ec0..00929c26186 100644 --- a/src/infra/device-identity.state-dir.test.ts +++ b/src/infra/device-identity.state-dir.test.ts @@ -49,4 +49,25 @@ describe("device identity state dir defaults", () => { expect(stored.deviceId).toBe(original.deviceId); }); }); + + it("regenerates the identity when the stored file is invalid", async () => { + await withStateDirEnv("openclaw-identity-state-", async ({ stateDir }) => { + const identityPath = path.join(stateDir, "identity", "device.json"); + await fs.mkdir(path.dirname(identityPath), { recursive: true }); + await fs.writeFile(identityPath, '{"version":1,"deviceId":"broken"}\n', "utf8"); + + const regenerated = loadOrCreateDeviceIdentity(); + const stored = JSON.parse(await fs.readFile(identityPath, "utf8")) as { + version?: number; + deviceId?: string; + publicKeyPem?: string; + privateKeyPem?: string; + }; + + expect(stored.version).toBe(1); + expect(stored.deviceId).toBe(regenerated.deviceId); + expect(stored.publicKeyPem).toBe(regenerated.publicKeyPem); + expect(stored.privateKeyPem).toBe(regenerated.privateKeyPem); + }); + }); }); diff --git a/src/infra/state-migrations.state-dir.test.ts b/src/infra/state-migrations.state-dir.test.ts index 8c46fe398e0..c270e30475f 100644 --- a/src/infra/state-migrations.state-dir.test.ts +++ b/src/infra/state-migrations.state-dir.test.ts @@ -49,4 +49,47 @@ describe("legacy state dir auto-migration", () => { expect(fs.readFileSync(path.join(root, ".moltbot", "marker.txt"), "utf-8")).toBe("ok"); expect(fs.readFileSync(path.join(root, ".clawdbot", "marker.txt"), "utf-8")).toBe("ok"); }); + + it("skips state-dir migration when OPENCLAW_STATE_DIR is explicitly set", async () => { + const root = await makeTempRoot(); + const legacyDir = path.join(root, ".clawdbot"); + fs.mkdirSync(legacyDir, { recursive: true }); + + const result = await autoMigrateLegacyStateDir({ + env: { OPENCLAW_STATE_DIR: path.join(root, "custom-state") } as NodeJS.ProcessEnv, + homedir: () => root, + }); + + expect(result).toEqual({ + migrated: false, + skipped: true, + changes: [], + warnings: [], + }); + expect(fs.existsSync(legacyDir)).toBe(true); + }); + + it("only runs once per process until reset", async () => { + const root = await makeTempRoot(); + const legacyDir = path.join(root, ".clawdbot"); + fs.mkdirSync(legacyDir, { recursive: true }); + fs.writeFileSync(path.join(legacyDir, "marker.txt"), "ok", "utf-8"); + + const first = await autoMigrateLegacyStateDir({ + env: {} as NodeJS.ProcessEnv, + homedir: () => root, + }); + const second = await autoMigrateLegacyStateDir({ + env: {} as NodeJS.ProcessEnv, + homedir: () => root, + }); + + expect(first.migrated).toBe(true); + expect(second).toEqual({ + migrated: false, + skipped: true, + changes: [], + warnings: [], + }); + }); });