fix: honor legacy setup dm policy accounts

This commit is contained in:
Tak Hoffman
2026-04-03 10:34:08 -05:00
parent 904d9db132
commit 3d8a039149
4 changed files with 242 additions and 20 deletions

View File

@@ -0,0 +1,56 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { describe, expect, it } from "vitest";
import { discordSetupWizard } from "./setup-surface.js";
describe("discordSetupWizard.dmPolicy", () => {
it("reads the named-account DM policy instead of the channel root", () => {
expect(
discordSetupWizard.dmPolicy?.getCurrent(
{
channels: {
discord: {
dmPolicy: "disabled",
accounts: {
alerts: {
dmPolicy: "allowlist",
token: "discord-token",
},
},
},
},
} as OpenClawConfig,
"alerts",
),
).toBe("allowlist");
});
it("reports account-scoped config keys for named accounts", () => {
expect(discordSetupWizard.dmPolicy?.resolveConfigKeys?.({}, "alerts")).toEqual({
policyKey: "channels.discord.accounts.alerts.dmPolicy",
allowFromKey: "channels.discord.accounts.alerts.allowFrom",
});
});
it('writes open policy state to the named account and preserves inherited allowFrom with "*"', () => {
const next = discordSetupWizard.dmPolicy?.setPolicy(
{
channels: {
discord: {
allowFrom: ["123"],
accounts: {
alerts: {
token: "discord-token",
},
},
},
},
} as OpenClawConfig,
"open",
"alerts",
);
expect(next?.channels?.discord?.dmPolicy).toBeUndefined();
expect(next?.channels?.discord?.accounts?.alerts?.dmPolicy).toBe("open");
expect(next?.channels?.discord?.accounts?.alerts?.allowFrom).toEqual(["123", "*"]);
});
});

View File

@@ -63,3 +63,58 @@ describe("slackSetupWizard.finalize", () => {
).toBe(true);
});
});
describe("slackSetupWizard.dmPolicy", () => {
it("reads the named-account DM policy instead of the channel root", () => {
expect(
slackSetupWizard.dmPolicy?.getCurrent(
{
channels: {
slack: {
dmPolicy: "disabled",
accounts: {
alerts: {
dmPolicy: "allowlist",
botToken: "xoxb-alerts",
appToken: "xapp-alerts",
},
},
},
},
} as OpenClawConfig,
"alerts",
),
).toBe("allowlist");
});
it("reports account-scoped config keys for named accounts", () => {
expect(slackSetupWizard.dmPolicy?.resolveConfigKeys?.({}, "alerts")).toEqual({
policyKey: "channels.slack.accounts.alerts.dmPolicy",
allowFromKey: "channels.slack.accounts.alerts.allowFrom",
});
});
it('writes open policy state to the named account and preserves inherited allowFrom with "*"', () => {
const next = slackSetupWizard.dmPolicy?.setPolicy(
{
channels: {
slack: {
allowFrom: ["U123"],
accounts: {
alerts: {
botToken: "xoxb-alerts",
appToken: "xapp-alerts",
},
},
},
},
} as OpenClawConfig,
"open",
"alerts",
);
expect(next?.channels?.slack?.dmPolicy).toBeUndefined();
expect(next?.channels?.slack?.accounts?.alerts?.dmPolicy).toBe("open");
expect(next?.channels?.slack?.accounts?.alerts?.allowFrom).toEqual(["U123", "*"]);
});
});

View File

@@ -1509,6 +1509,55 @@ describe("createLegacyCompatChannelDmPolicy", () => {
expect(next.channels?.slack?.dmPolicy).toBe("open");
expect(next.channels?.slack?.allowFrom).toEqual(["U123", "*"]);
});
it("honors named-account dm policy state and paths", () => {
const dmPolicy = createLegacyCompatChannelDmPolicy({
label: "Slack",
channel: "slack",
});
expect(
dmPolicy.getCurrent(
{
channels: {
slack: {
dmPolicy: "disabled",
accounts: {
alerts: {
dmPolicy: "allowlist",
},
},
},
},
},
"alerts",
),
).toBe("allowlist");
expect(dmPolicy.resolveConfigKeys?.({}, "alerts")).toEqual({
policyKey: "channels.slack.accounts.alerts.dmPolicy",
allowFromKey: "channels.slack.accounts.alerts.allowFrom",
});
const next = dmPolicy.setPolicy(
{
channels: {
slack: {
allowFrom: ["U123"],
accounts: {
alerts: {},
},
},
},
},
"open",
"alerts",
);
expect(next.channels?.slack?.dmPolicy).toBeUndefined();
expect(next.channels?.slack?.accounts?.alerts?.dmPolicy).toBe("open");
expect(next.channels?.slack?.accounts?.alerts?.allowFrom).toEqual(["U123", "*"]);
});
});
describe("createTopLevelChannelGroupPolicySetter", () => {

View File

@@ -629,30 +629,92 @@ export function createLegacyCompatChannelDmPolicy(params: {
channel: params.channel,
policyKey: `channels.${params.channel}.dmPolicy`,
allowFromKey: `channels.${params.channel}.allowFrom`,
getCurrent: (cfg) =>
(
cfg.channels?.[params.channel] as
resolveConfigKeys: (_cfg, accountId) =>
accountId && accountId !== DEFAULT_ACCOUNT_ID
? {
policyKey: `channels.${params.channel}.accounts.${accountId}.dmPolicy`,
allowFromKey: `channels.${params.channel}.accounts.${accountId}.allowFrom`,
}
: {
policyKey: `channels.${params.channel}.dmPolicy`,
allowFromKey: `channels.${params.channel}.allowFrom`,
},
getCurrent: (cfg, accountId) => {
const channelConfig =
(cfg.channels?.[params.channel] as
| {
dmPolicy?: DmPolicy;
dm?: { policy?: DmPolicy };
accounts?: Record<string, { dmPolicy?: DmPolicy; dm?: { policy?: DmPolicy } }>;
}
| undefined
)?.dmPolicy ??
(
cfg.channels?.[params.channel] as
| {
dmPolicy?: DmPolicy;
dm?: { policy?: DmPolicy };
}
| undefined
)?.dm?.policy ??
"pairing",
setPolicy: (cfg, policy) =>
setLegacyChannelDmPolicyWithAllowFrom({
cfg,
channel: params.channel,
dmPolicy: policy,
}),
| undefined) ?? {};
const accountConfig =
accountId && accountId !== DEFAULT_ACCOUNT_ID ? channelConfig.accounts?.[accountId] : undefined;
return accountConfig?.dmPolicy ??
accountConfig?.dm?.policy ??
channelConfig.dmPolicy ??
channelConfig.dm?.policy ??
"pairing";
},
setPolicy: (cfg, policy, accountId) =>
accountId && accountId !== DEFAULT_ACCOUNT_ID
? patchChannelConfigForAccount({
cfg,
channel: params.channel,
accountId,
patch: {
dmPolicy: policy,
...(policy === "open"
? {
allowFrom: addWildcardAllowFrom(
(
cfg.channels?.[params.channel] as
| {
accounts?: Record<
string,
{
allowFrom?: Array<string | number>;
dm?: { allowFrom?: Array<string | number> };
}
>;
}
| undefined
)?.accounts?.[accountId]?.allowFrom ??
(
cfg.channels?.[params.channel] as
| {
allowFrom?: Array<string | number>;
dm?: { allowFrom?: Array<string | number> };
}
| undefined
)?.allowFrom ??
(
cfg.channels?.[params.channel] as
| {
accounts?: Record<
string,
{ dm?: { allowFrom?: Array<string | number> } }
>;
}
| undefined
)?.accounts?.[accountId]?.dm?.allowFrom ??
(
cfg.channels?.[params.channel] as
| {
dm?: { allowFrom?: Array<string | number> };
}
| undefined
)?.dm?.allowFrom,
),
}
: {}),
},
})
: setLegacyChannelDmPolicyWithAllowFrom({
cfg,
channel: params.channel,
dmPolicy: policy,
}),
...(params.promptAllowFrom ? { promptAllowFrom: params.promptAllowFrom } : {}),
};
}