diff --git a/docs/channels/matrix.md b/docs/channels/matrix.md index 6d758d3e931..a7c797e88b5 100644 --- a/docs/channels/matrix.md +++ b/docs/channels/matrix.md @@ -574,7 +574,7 @@ Live directory lookup uses the logged-in Matrix account: - `ackReactionScope`: optional ack reaction scope override (`group-mentions`, `group-all`, `direct`, `all`, `none`, `off`). - `reactionNotifications`: inbound reaction notification mode (`own`, `off`). - `mediaMaxMb`: outbound media size cap in MB. -- `autoJoin`: invite auto-join policy (`always`, `allowlist`, `off`). +- `autoJoin`: invite auto-join policy (`always`, `allowlist`, `off`). Default: `off`. - `autoJoinAllowlist`: rooms/aliases allowed when `autoJoin` is `allowlist`. - `dm`: DM policy block (`enabled`, `policy`, `allowFrom`). - `dm.allowFrom` entries should be full Matrix user IDs unless you already resolved them through live directory lookup. diff --git a/extensions/matrix/src/channel.directory.test.ts b/extensions/matrix/src/channel.directory.test.ts index ca87d59647e..8f79f592db8 100644 --- a/extensions/matrix/src/channel.directory.test.ts +++ b/extensions/matrix/src/channel.directory.test.ts @@ -258,7 +258,6 @@ describe("matrix directory", () => { }), ).toEqual([ '- Matrix rooms: groupPolicy="open" allows any room to trigger (mention-gated). Set channels.matrix.groupPolicy="allowlist" + channels.matrix.groups (and optionally channels.matrix.groupAllowFrom) to restrict rooms.', - '- Matrix invites: autoJoin="always" joins any invited room before message policy applies. Set channels.matrix.autoJoin="allowlist" + channels.matrix.autoJoinAllowlist (or channels.matrix.autoJoin="off") to restrict joins.', ]); expect( @@ -293,17 +292,17 @@ describe("matrix directory", () => { }), ).toEqual([ '- Matrix rooms: groupPolicy="open" allows any room to trigger (mention-gated). Set channels.matrix.accounts.assistant.groupPolicy="allowlist" + channels.matrix.accounts.assistant.groups (and optionally channels.matrix.accounts.assistant.groupAllowFrom) to restrict rooms.', - '- Matrix invites: autoJoin="always" joins any invited room before message policy applies. Set channels.matrix.accounts.assistant.autoJoin="allowlist" + channels.matrix.accounts.assistant.autoJoinAllowlist (or channels.matrix.accounts.assistant.autoJoin="off") to restrict joins.', ]); }); - it("reports invite auto-join warnings even when room policy is restricted", () => { + it("reports invite auto-join warnings only when explicitly enabled", () => { expect( matrixPlugin.security?.collectWarnings?.({ cfg: { channels: { matrix: { groupPolicy: "allowlist", + autoJoin: "always", }, }, } as CoreConfig, @@ -312,6 +311,7 @@ describe("matrix directory", () => { channels: { matrix: { groupPolicy: "allowlist", + autoJoin: "always", }, }, } as CoreConfig, diff --git a/extensions/matrix/src/channel.ts b/extensions/matrix/src/channel.ts index 2fc7335b713..38b82469ade 100644 --- a/extensions/matrix/src/channel.ts +++ b/extensions/matrix/src/channel.ts @@ -165,7 +165,7 @@ export const matrixPlugin: ChannelPlugin = { `- Matrix rooms: groupPolicy="open" allows any room to trigger (mention-gated). Set ${configPath}.groupPolicy="allowlist" + ${configPath}.groups (and optionally ${configPath}.groupAllowFrom) to restrict rooms.`, ); } - if ((account.config.autoJoin ?? "always") === "always") { + if ((account.config.autoJoin ?? "off") === "always") { warnings.push( `- Matrix invites: autoJoin="always" joins any invited room before message policy applies. Set ${configPath}.autoJoin="allowlist" + ${configPath}.autoJoinAllowlist (or ${configPath}.autoJoin="off") to restrict joins.`, ); diff --git a/extensions/matrix/src/matrix/monitor/auto-join.test.ts b/extensions/matrix/src/matrix/monitor/auto-join.test.ts index 8cbc082ffd7..ebe36144a5e 100644 --- a/extensions/matrix/src/matrix/monitor/auto-join.test.ts +++ b/extensions/matrix/src/matrix/monitor/auto-join.test.ts @@ -58,6 +58,22 @@ describe("registerMatrixAutoJoin", () => { expect(joinRoom).toHaveBeenCalledWith("!room:example.org"); }); + it("does not auto-join invites by default", async () => { + const { client, getInviteHandler, joinRoom } = createClientStub(); + + registerMatrixAutoJoin({ + client, + accountConfig: {}, + runtime: { + log: vi.fn(), + error: vi.fn(), + } as unknown as import("openclaw/plugin-sdk/matrix").RuntimeEnv, + }); + + expect(getInviteHandler()).toBeNull(); + expect(joinRoom).not.toHaveBeenCalled(); + }); + it("ignores invites outside allowlist when autoJoin=allowlist", async () => { const { client, getInviteHandler, joinRoom, resolveRoom } = createClientStub(); resolveRoom.mockResolvedValue(null); diff --git a/extensions/matrix/src/matrix/monitor/auto-join.ts b/extensions/matrix/src/matrix/monitor/auto-join.ts index 9df9d7f3b7b..4357975ad5d 100644 --- a/extensions/matrix/src/matrix/monitor/auto-join.ts +++ b/extensions/matrix/src/matrix/monitor/auto-join.ts @@ -16,7 +16,7 @@ export function registerMatrixAutoJoin(params: { } runtime.log?.(message); }; - const autoJoin = accountConfig.autoJoin ?? "always"; + const autoJoin = accountConfig.autoJoin ?? "off"; const rawAllowlist = (accountConfig.autoJoinAllowlist ?? []) .map((entry) => String(entry).trim()) .filter(Boolean); diff --git a/extensions/matrix/src/types.ts b/extensions/matrix/src/types.ts index 962fb0f3169..9f5e205a337 100644 --- a/extensions/matrix/src/types.ts +++ b/extensions/matrix/src/types.ts @@ -109,7 +109,7 @@ export type MatrixConfig = { startupVerificationCooldownHours?: number; /** Max outbound media size in MB. */ mediaMaxMb?: number; - /** Auto-join invites (always|allowlist|off). Default: always. */ + /** Auto-join invites (always|allowlist|off). Default: off. */ autoJoin?: "always" | "allowlist" | "off"; /** Allowlist for auto-join invites (room IDs, aliases). */ autoJoinAllowlist?: Array;