fix(doctor): align matrix and zalouser allowlist semantics (#52096)

* fix(doctor): align extension allowlist semantics

* fix(doctor): skip generic zalouser group warning
This commit is contained in:
Vincent Koc
2026-03-22 08:19:24 -07:00
committed by GitHub
parent 52a0aa0672
commit 4685fc7e77
6 changed files with 73 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
export type AllowFromMode = "topOnly" | "topOrNested" | "nestedOnly";
export function resolveAllowFromMode(channelName: string): AllowFromMode {
if (channelName === "googlechat") {
if (channelName === "googlechat" || channelName === "matrix") {
return "nestedOnly";
}
if (channelName === "discord" || channelName === "slack") {

View File

@@ -0,0 +1,36 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { maybeRepairAllowlistPolicyAllowFrom } from "./allowlist-policy-repair.js";
const { readChannelAllowFromStoreMock } = vi.hoisted(() => ({
readChannelAllowFromStoreMock: vi.fn(),
}));
vi.mock("../../../pairing/pairing-store.js", () => ({
readChannelAllowFromStore: readChannelAllowFromStoreMock,
}));
describe("doctor allowlist-policy repair", () => {
beforeEach(() => {
readChannelAllowFromStoreMock.mockReset();
});
it("restores matrix dm allowFrom from the pairing store into the nested path", async () => {
readChannelAllowFromStoreMock.mockResolvedValue(["@alice:example.org"]);
const result = await maybeRepairAllowlistPolicyAllowFrom({
channels: {
matrix: {
dm: {
policy: "allowlist",
},
},
},
});
expect(result.changes).toEqual([
'- channels.matrix.dm.allowFrom: restored 1 sender entry from pairing store (dmPolicy="allowlist").',
]);
expect(result.config.channels?.matrix?.dm?.allowFrom).toEqual(["@alice:example.org"]);
expect(result.config.channels?.matrix?.allowFrom).toBeUndefined();
});
});

View File

@@ -28,6 +28,17 @@ describe("doctor empty allowlist policy warnings", () => {
]);
});
it("stays quiet for zalouser hybrid route-and-sender group access", () => {
const warnings = collectEmptyAllowlistPolicyWarningsForAccount({
account: { groupPolicy: "allowlist" },
channelName: "zalouser",
doctorFixCommand: "openclaw doctor --fix",
prefix: "channels.zalouser",
});
expect(warnings).toEqual([]);
});
it("stays quiet for channels that do not use sender-based group allowlists", () => {
const warnings = collectEmptyAllowlistPolicyWarningsForAccount({
account: { groupPolicy: "allowlist" },

View File

@@ -15,7 +15,12 @@ function usesSenderBasedGroupAllowlist(channelName?: string): boolean {
}
// These channels enforce group access via channel/space config, not sender-based
// groupAllowFrom lists.
return !(channelName === "discord" || channelName === "slack" || channelName === "googlechat");
return !(
channelName === "discord" ||
channelName === "slack" ||
channelName === "googlechat" ||
channelName === "zalouser"
);
}
function allowsGroupAllowFromFallback(channelName?: string): boolean {

View File

@@ -37,6 +37,24 @@ describe("doctor open-policy allowFrom repair", () => {
expect(result.config.channels?.googlechat?.dm?.allowFrom).toEqual(["*"]);
});
it("repairs nested-only matrix dm allowFrom", () => {
const result = maybeRepairOpenPolicyAllowFrom({
channels: {
matrix: {
dm: {
policy: "open",
},
},
},
});
expect(result.changes).toEqual([
'- channels.matrix.dm.allowFrom: set to ["*"] (required by dmPolicy="open")',
]);
expect(result.config.channels?.matrix?.dm?.allowFrom).toEqual(["*"]);
expect(result.config.channels?.matrix?.allowFrom).toBeUndefined();
});
it("appends wildcard to discord nested dm allowFrom when top-level is absent", () => {
const result = maybeRepairOpenPolicyAllowFrom({
channels: {