mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-22 23:41:07 +00:00
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:
@@ -111,6 +111,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Models/openai-completions: default non-native OpenAI-compatible providers to omit tool-definition `strict` fields unless users explicitly opt back in, so tool calling keeps working on providers that reject that option. (#45497) Thanks @sahancava.
|
||||
- Telegram/setup: warn when setup leaves DMs on pairing without an allowlist, and show valid account-scoped remediation commands. (#50710) Thanks @ernestodeoliveira.
|
||||
- Doctor/Telegram: replace the fresh-install empty group-allowlist false positive with first-run guidance that explains DM pairing approval and the next group setup steps, so new Telegram installs get actionable setup help instead of a broken-config warning. Thanks @vincentkoc.
|
||||
- Doctor/extensions: keep Matrix DM `allowFrom` repairs on the canonical `dm.allowFrom` path and stop treating Zalouser group sender gating as if it fell back to `allowFrom`, so doctor warnings and `--fix` stay aligned with runtime access control. Thanks @vincentkoc.
|
||||
- Models/OpenRouter runtime capabilities: fetch uncatalogued OpenRouter model metadata on first use so newly added vision models keep image input instead of silently degrading to text-only, with top-level capability field fallbacks for `/api/v1/models`. (#45824) Thanks @DJjjjhao.
|
||||
- Channels/plugins: keep shared interactive payloads merge-ready by fixing Slack custom callback routing and repeat-click dedupe, allowing interactive-only sends, and preserving ordered Discord shared text blocks. (#47715) Thanks @vincentkoc.
|
||||
- Slack/interactive replies: preserve `channelData.slack.blocks` through live DM delivery and preview-finalized edits so Block Kit button and select directives render instead of falling back to raw text. (#45890) Thanks @vincentkoc.
|
||||
|
||||
@@ -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") {
|
||||
|
||||
36
src/commands/doctor/shared/allowlist-policy-repair.test.ts
Normal file
36
src/commands/doctor/shared/allowlist-policy-repair.test.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
@@ -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" },
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user