Files
openclaw/extensions/matrix/src/migration-config.test.ts
2026-05-08 17:03:43 +01:00

239 lines
6.8 KiB
TypeScript

import path from "node:path";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import { withTempHome } from "openclaw/plugin-sdk/test-env";
import { describe, expect, it } from "vitest";
import { resolveMatrixMigrationAccountTarget } from "./migration-config.js";
import {
MATRIX_OPS_ACCESS_TOKEN,
MATRIX_OPS_ACCOUNT_ID,
MATRIX_OPS_USER_ID,
MATRIX_TEST_HOMESERVER,
writeMatrixCredentials,
} from "./test-helpers.js";
function resolveOpsTarget(cfg: OpenClawConfig, env = process.env) {
return resolveMatrixMigrationAccountTarget({
cfg,
env,
accountId: MATRIX_OPS_ACCOUNT_ID,
});
}
type MatrixMigrationTarget = NonNullable<ReturnType<typeof resolveOpsTarget>>;
function expectMigrationTarget(target: ReturnType<typeof resolveOpsTarget>): MatrixMigrationTarget {
expect(target).toEqual(expect.objectContaining({ homeserver: expect.any(String) }));
if (target === null) {
throw new Error("Expected Matrix migration account target");
}
return target;
}
describe("resolveMatrixMigrationAccountTarget", () => {
it("reuses stored user identity for token-only configs when the access token matches", async () => {
await withTempHome(async (home) => {
const stateDir = path.join(home, ".openclaw");
writeMatrixCredentials(stateDir, {
accountId: MATRIX_OPS_ACCOUNT_ID,
deviceId: "DEVICE-OPS",
accessToken: MATRIX_OPS_ACCESS_TOKEN,
});
const cfg: OpenClawConfig = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: MATRIX_TEST_HOMESERVER,
accessToken: MATRIX_OPS_ACCESS_TOKEN,
},
},
},
},
};
const target = resolveOpsTarget(cfg);
const migrationTarget = expectMigrationTarget(target);
expect(migrationTarget.userId).toBe(MATRIX_OPS_USER_ID);
expect(migrationTarget.storedDeviceId).toBe("DEVICE-OPS");
});
});
it("ignores stored device IDs from stale cached Matrix credentials", async () => {
await withTempHome(async (home) => {
const stateDir = path.join(home, ".openclaw");
writeMatrixCredentials(stateDir, {
accountId: MATRIX_OPS_ACCOUNT_ID,
userId: "@old-bot:example.org",
accessToken: "tok-old",
deviceId: "DEVICE-OLD",
});
const cfg: OpenClawConfig = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: MATRIX_TEST_HOMESERVER,
userId: "@new-bot:example.org",
accessToken: "tok-new",
},
},
},
},
};
const target = resolveOpsTarget(cfg);
const migrationTarget = expectMigrationTarget(target);
expect(migrationTarget.userId).toBe("@new-bot:example.org");
expect(migrationTarget.accessToken).toBe("tok-new");
expect(migrationTarget.storedDeviceId).toBeNull();
});
});
it("does not trust stale stored creds on the same homeserver when the token changes", async () => {
await withTempHome(async (home) => {
const stateDir = path.join(home, ".openclaw");
writeMatrixCredentials(stateDir, {
accountId: MATRIX_OPS_ACCOUNT_ID,
userId: "@old-bot:example.org",
accessToken: "tok-old",
deviceId: "DEVICE-OLD",
});
const cfg: OpenClawConfig = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: MATRIX_TEST_HOMESERVER,
accessToken: "tok-new",
},
},
},
},
};
const target = resolveOpsTarget(cfg);
expect(target).toBeNull();
});
});
it("does not inherit the base userId for non-default token-only accounts", async () => {
await withTempHome(async (home) => {
const stateDir = path.join(home, ".openclaw");
writeMatrixCredentials(stateDir, {
accountId: MATRIX_OPS_ACCOUNT_ID,
deviceId: "DEVICE-OPS",
accessToken: MATRIX_OPS_ACCESS_TOKEN,
});
const cfg: OpenClawConfig = {
channels: {
matrix: {
homeserver: MATRIX_TEST_HOMESERVER,
userId: "@base-bot:example.org",
accounts: {
ops: {
homeserver: MATRIX_TEST_HOMESERVER,
accessToken: MATRIX_OPS_ACCESS_TOKEN,
},
},
},
},
};
const target = resolveOpsTarget(cfg);
const migrationTarget = expectMigrationTarget(target);
expect(migrationTarget.userId).toBe(MATRIX_OPS_USER_ID);
expect(migrationTarget.storedDeviceId).toBe("DEVICE-OPS");
});
});
it("does not inherit the base access token for non-default accounts", async () => {
await withTempHome(async () => {
const cfg: OpenClawConfig = {
channels: {
matrix: {
homeserver: MATRIX_TEST_HOMESERVER,
userId: "@base-bot:example.org",
accessToken: "tok-base",
accounts: {
ops: {
homeserver: MATRIX_TEST_HOMESERVER,
userId: MATRIX_OPS_USER_ID,
},
},
},
},
};
const target = resolveOpsTarget(cfg);
expect(target).toBeNull();
});
});
it("does not inherit the global Matrix access token for non-default accounts", async () => {
await withTempHome(
async () => {
const cfg: OpenClawConfig = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: MATRIX_TEST_HOMESERVER,
userId: MATRIX_OPS_USER_ID,
},
},
},
},
};
const target = resolveOpsTarget(cfg);
expect(target).toBeNull();
},
{
env: {
MATRIX_ACCESS_TOKEN: "tok-global",
},
},
);
});
it("uses the same scoped env token encoding as runtime account auth", async () => {
await withTempHome(async () => {
const cfg: OpenClawConfig = {
channels: {
matrix: {
accounts: {
"ops-prod": {},
},
},
},
};
const env = {
MATRIX_OPS_X2D_PROD_HOMESERVER: "https://matrix.example.org",
MATRIX_OPS_X2D_PROD_USER_ID: "@ops-prod:example.org",
MATRIX_OPS_X2D_PROD_ACCESS_TOKEN: "tok-ops-prod",
} as NodeJS.ProcessEnv;
const target = resolveMatrixMigrationAccountTarget({
cfg,
env,
accountId: "ops-prod",
});
const migrationTarget = expectMigrationTarget(target);
expect(migrationTarget.homeserver).toBe("https://matrix.example.org");
expect(migrationTarget.userId).toBe("@ops-prod:example.org");
expect(migrationTarget.accessToken).toBe("tok-ops-prod");
});
});
});