fix(matrix): avoid persistent probe storage

This commit is contained in:
Gustavo Madeira Santana 2026-04-06 00:28:47 -04:00
parent 8a7eb2329a
commit cd7a1001df
5 changed files with 66 additions and 34 deletions

View File

@ -244,7 +244,7 @@ Docs: https://docs.openclaw.ai
- Plugins/facades: resolve globally installed bundled-plugin runtime facades from registry roots so bundled channels like LINE still boot when the winning plugin install lives under the global extensions directory with an encoded scoped folder name. (#61297) Thanks @openperf.
- Matrix: avoid failing startup when token auth already knows the user ID but still needs optional device metadata, retry transient auth bootstrap requests, and backfill missing device IDs after startup while keeping unknown-device storage reuse conservative until metadata is repaired. (#61383) Thanks @gumadeiras.
- Agents/exec: stop streaming `tool_execution_update` events after an exec session backgrounds, preventing delayed background output from hitting a stale listener and crashing the gateway while keeping the output available through `process poll/log`. (#61627) Thanks @openperf.
- Matrix: pass configured `deviceId` through health probes and keep probe-only client setup from rewriting `storage-meta.json`, so health checks preserve the correct device identity during probe cycles. (#61581) thanks @MoerAI.
- Matrix: pass configured `deviceId` through health probes and keep probe-only client setup out of durable Matrix storage, so health checks preserve the correct device identity without rewriting `storage-meta.json` or related probe state on disk. (#61581) thanks @MoerAI.
## 2026.4.2

View File

@ -68,18 +68,48 @@ describe("createMatrixClient", () => {
accountId: undefined,
deviceId: undefined,
});
expect(MatrixClientMock).toHaveBeenCalledTimes(1);
expect(resolveMatrixStoragePathsMock).toHaveBeenCalledTimes(1);
expect(MatrixClientMock).toHaveBeenCalledWith("https://matrix.example.org", "tok", {
userId: "@bot:example.org",
password: undefined,
deviceId: undefined,
encryption: undefined,
localTimeoutMs: undefined,
initialSyncLimit: undefined,
storagePath: storagePaths.storagePath,
recoveryKeyPath: storagePaths.recoveryKeyPath,
idbSnapshotPath: storagePaths.idbSnapshotPath,
cryptoDatabasePrefix: "openclaw-matrix-default-token-hash",
autoBootstrapCrypto: undefined,
ssrfPolicy: undefined,
dispatcherPolicy: undefined,
});
});
it("skips storage metadata writes when persistence is disabled", async () => {
it("skips persistent storage wiring when persistence is disabled", async () => {
await createMatrixClient({
homeserver: "https://matrix.example.org",
userId: "@bot:example.org",
accessToken: "tok",
persistStorageMeta: false,
persistStorage: false,
});
expect(resolveMatrixStoragePathsMock).not.toHaveBeenCalled();
expect(writeStorageMetaMock).not.toHaveBeenCalled();
expect(MatrixClientMock).toHaveBeenCalledTimes(1);
expect(MatrixClientMock).toHaveBeenCalledWith("https://matrix.example.org", "tok", {
userId: "@bot:example.org",
password: undefined,
deviceId: undefined,
encryption: undefined,
localTimeoutMs: undefined,
initialSyncLimit: undefined,
storagePath: undefined,
recoveryKeyPath: undefined,
idbSnapshotPath: undefined,
cryptoDatabasePrefix: undefined,
autoBootstrapCrypto: undefined,
ssrfPolicy: undefined,
dispatcherPolicy: undefined,
});
});
});

View File

@ -33,7 +33,7 @@ export async function createMatrixClient(params: {
accessToken: string;
password?: string;
deviceId?: string;
persistStorageMeta?: boolean;
persistStorage?: boolean;
encryption?: boolean;
localTimeoutMs?: number;
initialSyncLimit?: number;
@ -46,29 +46,29 @@ export async function createMatrixClient(params: {
const { MatrixClient, ensureMatrixSdkLoggingConfigured } =
await loadMatrixCreateClientRuntimeDeps();
ensureMatrixSdkLoggingConfigured();
const env = process.env;
const homeserver = await resolveValidatedMatrixHomeserverUrl(params.homeserver, {
dangerouslyAllowPrivateNetwork: params.allowPrivateNetwork,
});
const userId = params.userId?.trim() || "unknown";
const matrixClientUserId = params.userId?.trim() || undefined;
const persistStorage = params.persistStorage !== false;
const storagePaths = persistStorage
? resolveMatrixStoragePaths({
homeserver,
userId,
accessToken: params.accessToken,
accountId: params.accountId,
deviceId: params.deviceId,
env: process.env,
})
: null;
const storagePaths = resolveMatrixStoragePaths({
homeserver,
userId,
accessToken: params.accessToken,
accountId: params.accountId,
deviceId: params.deviceId,
env,
});
await maybeMigrateLegacyStorage({
storagePaths,
env,
});
fs.mkdirSync(storagePaths.rootDir, { recursive: true });
// Health probes still need validated paths, but they must not rewrite durable identity metadata.
if (params.persistStorageMeta !== false) {
if (storagePaths) {
await maybeMigrateLegacyStorage({
storagePaths,
env: process.env,
});
fs.mkdirSync(storagePaths.rootDir, { recursive: true });
writeStorageMeta({
storagePaths,
homeserver,
@ -78,7 +78,9 @@ export async function createMatrixClient(params: {
});
}
const cryptoDatabasePrefix = `openclaw-matrix-${storagePaths.accountKey}-${storagePaths.tokenHash}`;
const cryptoDatabasePrefix = storagePaths
? `openclaw-matrix-${storagePaths.accountKey}-${storagePaths.tokenHash}`
: undefined;
return new MatrixClient(homeserver, params.accessToken, {
userId: matrixClientUserId,
@ -87,9 +89,9 @@ export async function createMatrixClient(params: {
encryption: params.encryption,
localTimeoutMs: params.localTimeoutMs,
initialSyncLimit: params.initialSyncLimit,
storagePath: storagePaths.storagePath,
recoveryKeyPath: storagePaths.recoveryKeyPath,
idbSnapshotPath: storagePaths.idbSnapshotPath,
storagePath: storagePaths?.storagePath,
recoveryKeyPath: storagePaths?.recoveryKeyPath,
idbSnapshotPath: storagePaths?.idbSnapshotPath,
cryptoDatabasePrefix,
autoBootstrapCrypto: params.autoBootstrapCrypto,
ssrfPolicy: params.ssrfPolicy,

View File

@ -34,7 +34,7 @@ describe("probeMatrix", () => {
homeserver: "https://matrix.example.org",
userId: undefined,
accessToken: "tok",
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: 1234,
});
});
@ -51,7 +51,7 @@ describe("probeMatrix", () => {
homeserver: "https://matrix.example.org",
userId: "@bot:example.org",
accessToken: "tok",
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: 500,
});
});
@ -69,7 +69,7 @@ describe("probeMatrix", () => {
homeserver: "https://matrix.example.org",
userId: "@bot:example.org",
accessToken: "tok",
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: 500,
accountId: "ops",
});
@ -90,7 +90,7 @@ describe("probeMatrix", () => {
homeserver: "https://matrix.example.org",
userId: undefined,
accessToken: "tok",
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: 500,
dispatcherPolicy: {
mode: "explicit-proxy",
@ -114,7 +114,7 @@ describe("probeMatrix", () => {
userId: "@bot:example.org",
accessToken: "tok",
deviceId: "ABCDEF",
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: 500,
accountId: "ops",
});
@ -132,7 +132,7 @@ describe("probeMatrix", () => {
userId: undefined,
accessToken: "tok",
deviceId: undefined,
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: 500,
});
});

View File

@ -67,7 +67,7 @@ export async function probeMatrix(params: {
userId: inputUserId,
accessToken: params.accessToken,
deviceId: params.deviceId,
persistStorageMeta: false,
persistStorage: false,
localTimeoutMs: params.timeoutMs,
accountId: params.accountId,
allowPrivateNetwork: params.allowPrivateNetwork,