import { beforeEach, describe, expect, it } from
"vitest" ;
import { createRuntimeEnv } from
"../../../test/helpers/plugins/runtime-env.js" ;
import type { RuntimeEnv } from
"../runtime-api.js" ;
import { matrixPlugin } from
"./channel.js" ;
import { resolveMatrixAccount } from
"./matrix/accounts.js" ;
import { resolveMatrixConfigForAccount } from
"./matrix/client/config.js" ;
import { installMatrixTestRuntime } from
"./test-runtime.js" ;
import type { CoreConfig } from
"./types.js" ;
describe(
"matrix directory" , () => {
const runtimeEnv: RuntimeEnv = createRuntimeEnv();
beforeEach(() => {
installMatrixTestRuntime();
});
it(
"lists peers and groups from config" , async () => {
const cfg = {
channels: {
matrix: {
dm: { allowFrom: [
"matrix:@alice:example.org" ,
"bob" ] },
groupAllowFrom: [
"@dana:example.org" ],
groups: {
"!room1:example.org" : { users: [
"@carol:example.org" ] },
"#alias:example.org" : { users: [] },
},
},
},
} as unknown as CoreConfig;
expect(matrixPlugin.directory).toBeTruthy();
expect(matrixPlugin.directory?.listPeers).toBeTruthy();
expect(matrixPlugin.directory?.listGroups).toBeTruthy();
await expect(
matrixPlugin.directory!.listPeers!({
cfg,
accountId: undefined,
query: undefined,
limit: undefined,
runtime: runtimeEnv,
}),
).resolves.toEqual(
expect.arrayContaining([
{ kind:
"user" , id:
"user:@alice:example.org" },
{ kind:
"user" , id:
"bob" , name:
"incomplete id; expected @user:server" },
{ kind:
"user" , id:
"user:@carol:example.org" },
{ kind:
"user" , id:
"user:@dana:example.org" },
]),
);
await expect(
matrixPlugin.directory!.listGroups!({
cfg,
accountId: undefined,
query: undefined,
limit: undefined,
runtime: runtimeEnv,
}),
).resolves.toEqual(
expect.arrayContaining([
{ kind:
"group" , id:
"room:!room1:example.org" },
{ kind:
"group" , id:
"#alias:example.org" },
]),
);
});
it(
"resolves replyToMode from account config" , () => {
const cfg = {
channels: {
matrix: {
replyToMode:
"off" ,
accounts: {
Assistant: {
replyToMode:
"all" ,
},
},
},
},
} as unknown as CoreConfig;
expect(matrixPlugin.threading?.resolveReplyToMode).toBeTruthy();
expect(
matrixPlugin.threading?.resolveReplyToMode?.({
cfg,
accountId:
"assistant" ,
chatType:
"direct" ,
}),
).toBe(
"all" );
expect(
matrixPlugin.threading?.resolveReplyToMode?.({
cfg,
accountId:
"default" ,
chatType:
"direct" ,
}),
).toBe(
"off" );
});
it(
"only exposes real Matrix thread ids in tool context" , () => {
expect(
matrixPlugin.threading?.buildToolContext?.({
cfg: {} as CoreConfig,
context: {
To:
"room:!room:example.org" ,
ReplyToId:
"$reply" ,
},
hasRepliedRef: { value:
false },
}),
).toEqual({
currentChannelId:
"room:!room:example.org" ,
currentThreadTs: undefined,
hasRepliedRef: { value:
false },
});
expect(
matrixPlugin.threading?.buildToolContext?.({
cfg: {} as CoreConfig,
context: {
To:
"room:!room:example.org" ,
ReplyToId:
"$reply" ,
MessageThreadId:
"$thread" ,
},
hasRepliedRef: { value:
true },
}),
).toEqual({
currentChannelId:
"room:!room:example.org" ,
currentThreadTs:
"$thread" ,
hasRepliedRef: { value:
true },
});
});
it(
"exposes Matrix direct user id in dm tool context" , () => {
expect(
matrixPlugin.threading?.buildToolContext?.({
cfg: {} as CoreConfig,
context: {
From:
"matrix:@alice:example.org" ,
To:
"room:!dm:example.org" ,
ChatType:
"direct" ,
MessageThreadId:
"$thread" ,
},
hasRepliedRef: { value:
false },
}),
).toEqual({
currentChannelId:
"room:!dm:example.org" ,
currentThreadTs:
"$thread" ,
currentDirectUserId:
"@alice:example.org" ,
hasRepliedRef: { value:
false },
});
});
it(
"accepts raw room ids when inferring Matrix direct user ids" , () => {
expect(
matrixPlugin.threading?.buildToolContext?.({
cfg: {} as CoreConfig,
context: {
From:
"user:@alice:example.org" ,
To:
"!dm:example.org" ,
ChatType:
"direct" ,
},
hasRepliedRef: { value:
false },
}),
).toEqual({
currentChannelId:
"!dm:example.org" ,
currentThreadTs: undefined,
currentDirectUserId:
"@alice:example.org" ,
hasRepliedRef: { value:
false },
});
});
it(
"resolves group mention policy from account config" , () => {
const cfg = {
channels: {
matrix: {
groups: {
"!room:example.org" : { requireMention:
true },
},
accounts: {
Assistant: {
groups: {
"!room:example.org" : { requireMention:
false },
},
},
},
},
},
} as unknown as CoreConfig;
expect(matrixPlugin.groups!.resolveRequireMention!({ cfg, groupId:
"!room:example.org" })).toBe(
true ,
);
expect(
matrixPlugin.groups!.resolveRequireMention!({
cfg,
accountId:
"assistant" ,
groupId:
"!room:example.org" ,
}),
).toBe(
false );
expect(
matrixPlugin.groups!.resolveRequireMention!({
cfg,
accountId:
"assistant" ,
groupId:
"matrix:room:!room:example.org" ,
}),
).toBe(
false );
});
it(
"matches prefixed Matrix aliases in group context" , () => {
const cfg = {
channels: {
matrix: {
groups: {
"#ops:example.org" : { requireMention:
false },
},
},
},
} as unknown as CoreConfig;
expect(
matrixPlugin.groups!.resolveRequireMention!({
cfg,
groupId:
"matrix:room:!room:example.org" ,
groupChannel:
"matrix:channel:#ops:example.org" ,
}),
).toBe(
false );
});
it(
"reports room access warnings against the active Matrix config path" , () => {
expect(
matrixPlugin.security?.collectWarnings?.({
cfg: {
channels: {
matrix: {
groupPolicy:
"open" ,
},
},
} as CoreConfig,
account: resolveMatrixAccount({
cfg: {
channels: {
matrix: {
groupPolicy:
"open" ,
},
},
} as CoreConfig,
accountId:
"default" ,
}),
}),
).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.' ,
]);
expect(
matrixPlugin.security?.collectWarnings?.({
cfg: {
channels: {
matrix: {
defaultAccount:
"assistant" ,
accounts: {
assistant: {
groupPolicy:
"open" ,
},
},
},
},
} as CoreConfig,
account: resolveMatrixAccount({
cfg: {
channels: {
matrix: {
defaultAccount:
"assistant" ,
accounts: {
assistant: {
groupPolicy:
"open" ,
},
},
},
},
} as CoreConfig,
accountId:
"assistant" ,
}),
}),
).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.' ,
]);
});
it(
"reports invite auto-join warnings only when explicitly enabled" , () => {
expect(
matrixPlugin.security?.collectWarnings?.({
cfg: {
channels: {
matrix: {
groupPolicy:
"allowlist" ,
autoJoin:
"always" ,
},
},
} as CoreConfig,
account: resolveMatrixAccount({
cfg: {
channels: {
matrix: {
groupPolicy:
"allowlist" ,
autoJoin:
"always" ,
},
},
} as CoreConfig,
accountId:
"default" ,
}),
}),
).toEqual([
'- 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.' ,
]);
});
it(
"writes matrix non-default account credentials under channels.matrix.accounts" , () => {
const cfg = {
channels: {
matrix: {
homeserver:
"https://default.example.org ",
accessToken:
"default-token" ,
deviceId:
"DEFAULTDEVICE" ,
avatarUrl:
"mxc://server/avatar",
encryption:
true ,
threadReplies:
"inbound" ,
groups: {
"!room:example.org" : { requireMention:
true },
},
},
},
} as unknown as CoreConfig;
const updated = matrixPlugin.setup!.applyAccountConfig({
cfg,
accountId:
"ops" ,
input: {
homeserver:
"https://matrix.example.org ",
userId:
"@ops:example.org" ,
accessToken:
"ops-token" ,
},
}) as CoreConfig;
expect(updated.channels?.[
"matrix" ]?.accessToken).toBeUndefined();
expect(updated.channels?.[
"matrix" ]?.deviceId).toBeUndefined();
expect(updated.channels?.[
"matrix" ]?.avatarUrl).toBeUndefined();
expect(updated.channels?.[
"matrix" ]?.accounts?.
default ).toMatchObject({
accessToken:
"default-token" ,
homeserver:
"https://default.example.org ",
deviceId:
"DEFAULTDEVICE" ,
avatarUrl:
"mxc://server/avatar",
encryption:
true ,
threadReplies:
"inbound" ,
groups: {
"!room:example.org" : { requireMention:
true },
},
});
expect(updated.channels?.[
"matrix" ]?.accounts?.ops).toMatchObject({
enabled:
true ,
homeserver:
"https://matrix.example.org ",
userId:
"@ops:example.org" ,
accessToken:
"ops-token" ,
});
expect(resolveMatrixConfigForAccount(updated,
"ops" , {})).toMatchObject({
homeserver:
"https://matrix.example.org ",
userId:
"@ops:example.org" ,
accessToken:
"ops-token" ,
deviceId: undefined,
});
});
it(
"writes default matrix account credentials under channels.matrix.accounts.default" ,
() => {
const cfg = {
channels: {
matrix: {
homeserver: "https://legacy.example.org ",
accessToken: "legacy-token" ,
},
},
} as unknown as CoreConfig;
const updated = matrixPlugin.setup!.applyAccountConfig({
cfg,
accountId: "default" ,
input: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "bot-token" ,
},
}) as CoreConfig;
expect(updated.channels?.["matrix" ]).toMatchObject({
enabled: true ,
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
accessToken: "bot-token" ,
});
expect(updated.channels?.["matrix" ]?.accounts).toBeUndefined();
});
it("requires account-scoped env vars when --use-env is set for non-default accounts" , () => {
const envKeys = [
"MATRIX_OPS_HOMESERVER" ,
"MATRIX_OPS_USER_ID" ,
"MATRIX_OPS_ACCESS_TOKEN" ,
"MATRIX_OPS_PASSWORD" ,
] as const ;
const previousEnv = Object.fromEntries(envKeys.map((key) => [key, process.env[key]])) as Record<
(typeof envKeys)[number],
string | undefined
>;
for (const key of envKeys) {
delete process.env[key];
}
try {
const error = matrixPlugin.setup!.validateInput?.({
cfg: {} as CoreConfig,
accountId: "ops" ,
input: { useEnv: true },
});
expect(error).toBe(
'Set per-account env vars for "ops" (for example MATRIX_OPS_HOMESERVER + MATRIX_OPS_ACCESS_TOKEN or MATRIX_OPS_USER_ID + MATRIX_OPS_PASSWORD).' ,
);
} finally {
for (const key of envKeys) {
if (previousEnv[key] === undefined) {
delete process.env[key];
} else {
process.env[key] = previousEnv[key];
}
}
}
});
it("accepts --use-env for non-default account when scoped env vars are present" , () => {
const envKeys = {
MATRIX_OPS_HOMESERVER: process.env.MATRIX_OPS_HOMESERVER,
MATRIX_OPS_ACCESS_TOKEN: process.env.MATRIX_OPS_ACCESS_TOKEN,
};
process.env.MATRIX_OPS_HOMESERVER = "https://ops.example.org ";
process.env.MATRIX_OPS_ACCESS_TOKEN = "ops-token" ;
try {
const error = matrixPlugin.setup!.validateInput?.({
cfg: {} as CoreConfig,
accountId: "ops" ,
input: { useEnv: true },
});
expect(error).toBeNull();
} finally {
for (const [key, value] of Object.entries(envKeys)) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
});
it("clears stored auth fields when switching a Matrix account to env-backed auth" , () => {
const envKeys = {
MATRIX_OPS_HOMESERVER: process.env.MATRIX_OPS_HOMESERVER,
MATRIX_OPS_ACCESS_TOKEN: process.env.MATRIX_OPS_ACCESS_TOKEN,
MATRIX_OPS_DEVICE_ID: process.env.MATRIX_OPS_DEVICE_ID,
MATRIX_OPS_DEVICE_NAME: process.env.MATRIX_OPS_DEVICE_NAME,
};
process.env.MATRIX_OPS_HOMESERVER = "https://ops.env.example.org ";
process.env.MATRIX_OPS_ACCESS_TOKEN = "ops-env-token" ;
process.env.MATRIX_OPS_DEVICE_ID = "OPSENVDEVICE" ;
process.env.MATRIX_OPS_DEVICE_NAME = "Ops Env Device" ;
try {
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
homeserver: "https://ops.inline.example.org ",
userId: "@ops:inline.example.org" ,
accessToken: "ops-inline-token" ,
password: "ops-inline-password" , // pragma: allowlist secret
deviceId: "OPSINLINEDEVICE" ,
deviceName: "Ops Inline Device" ,
encryption: true ,
},
},
},
},
} as unknown as CoreConfig;
const updated = matrixPlugin.setup!.applyAccountConfig({
cfg,
accountId: "ops" ,
input: {
useEnv: true ,
name: "Ops" ,
},
}) as CoreConfig;
expect(updated.channels?.["matrix" ]?.accounts?.ops).toMatchObject({
name: "Ops" ,
enabled: true ,
encryption: true ,
});
expect(updated.channels?.["matrix" ]?.accounts?.ops?.homeserver).toBeUndefined();
expect(updated.channels?.["matrix" ]?.accounts?.ops?.userId).toBeUndefined();
expect(updated.channels?.["matrix" ]?.accounts?.ops?.accessToken).toBeUndefined();
expect(updated.channels?.["matrix" ]?.accounts?.ops?.password).toBeUndefined();
expect(updated.channels?.["matrix" ]?.accounts?.ops?.deviceId).toBeUndefined();
expect(updated.channels?.["matrix" ]?.accounts?.ops?.deviceName).toBeUndefined();
expect(resolveMatrixConfigForAccount(updated, "ops" , process.env)).toMatchObject({
homeserver: "https://ops.env.example.org ",
accessToken: "ops-env-token" ,
deviceId: "OPSENVDEVICE" ,
deviceName: "Ops Env Device" ,
});
} finally {
for (const [key, value] of Object.entries(envKeys)) {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
}
});
it("resolves account id from input name when explicit account id is missing" , () => {
const accountId = matrixPlugin.setup!.resolveAccountId?.({
cfg: {} as CoreConfig,
accountId: undefined,
input: { name: "Main Bot" },
});
expect(accountId).toBe("main-bot" );
});
it("resolves binding account id from agent id when omitted" , () => {
const accountId = matrixPlugin.setup!.resolveBindingAccountId?.({
cfg: {} as CoreConfig,
agentId: "Ops" ,
accountId: undefined,
});
expect(accountId).toBe("ops" );
});
it("clears stale access token when switching an account to password auth" , () => {
const cfg = {
channels: {
matrix: {
accounts: {
default : {
homeserver: "https://matrix.example.org ",
accessToken: "old-token" ,
},
},
},
},
} as unknown as CoreConfig;
const updated = matrixPlugin.setup!.applyAccountConfig({
cfg,
accountId: "default" ,
input: {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
password: "new-password" , // pragma: allowlist secret
},
}) as CoreConfig;
expect(updated.channels?.["matrix" ]?.accounts?.default ?.password).toBe("new-password" );
expect(updated.channels?.["matrix" ]?.accounts?.default ?.accessToken).toBeUndefined();
});
it("clears stale password when switching an account to token auth" , () => {
const cfg = {
channels: {
matrix: {
accounts: {
default : {
homeserver: "https://matrix.example.org ",
userId: "@bot:example.org" ,
password: "old-password" , // pragma: allowlist secret
},
},
},
},
} as unknown as CoreConfig;
const updated = matrixPlugin.setup!.applyAccountConfig({
cfg,
accountId: "default" ,
input: {
homeserver: "https://matrix.example.org ",
accessToken: "new-token" ,
},
}) as CoreConfig;
expect(updated.channels?.["matrix" ]?.accounts?.default ?.accessToken).toBe("new-token" );
expect(updated.channels?.["matrix" ]?.accounts?.default ?.password).toBeUndefined();
});
});
Messung V0.5 in Prozent C=97 H=92 G=94
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland