fix: honor zalouser setup dm policy accounts

This commit is contained in:
Tak Hoffman 2026-04-03 10:44:46 -05:00
parent 4107a5a4f0
commit 69d018ce4f
No known key found for this signature in database
2 changed files with 133 additions and 10 deletions

View File

@ -7,6 +7,7 @@ import {
import type { OpenClawConfig } from "../runtime-api.js";
import "./zalo-js.test-mocks.js";
import { zalouserPlugin } from "./channel.js";
import { zalouserSetupWizard } from "./setup-surface.js";
const zalouserConfigure = createPluginSetupWizardConfigure(zalouserPlugin);
@ -221,4 +222,89 @@ describe("zalouser setup wizard", () => {
expect(result.cfg.plugins?.entries?.zalouser?.enabled).toBe(true);
expect(result.cfg.plugins?.allow).toEqual(["telegram", "zalouser"]);
});
it("reads the named-account DM policy instead of the channel root", () => {
expect(
zalouserSetupWizard.dmPolicy?.getCurrent(
{
channels: {
zalouser: {
dmPolicy: "disabled",
accounts: {
work: {
profile: "work",
dmPolicy: "allowlist",
},
},
},
},
} as OpenClawConfig,
"work",
),
).toBe("allowlist");
});
it("reports account-scoped config keys for named accounts", () => {
expect(zalouserSetupWizard.dmPolicy?.resolveConfigKeys?.({} as OpenClawConfig, "work")).toEqual(
{
policyKey: "channels.zalouser.accounts.work.dmPolicy",
allowFromKey: "channels.zalouser.accounts.work.allowFrom",
},
);
});
it('writes open policy state to the named account and preserves inherited allowFrom with "*"', () => {
const next = zalouserSetupWizard.dmPolicy?.setPolicy(
{
channels: {
zalouser: {
allowFrom: ["123456789"],
accounts: {
work: {
profile: "work",
},
},
},
},
} as OpenClawConfig,
"open",
"work",
);
expect(next?.channels?.zalouser?.dmPolicy).toBeUndefined();
expect(next?.channels?.zalouser?.accounts?.work?.dmPolicy).toBe("open");
expect(next?.channels?.zalouser?.accounts?.work?.allowFrom).toEqual(["123456789", "*"]);
});
it("shows the account-scoped current DM policy in quickstart notes", async () => {
const note = vi.fn(async (_message: string, _title?: string) => {});
const prompter = createQuickstartPrompter({ note, dmPolicy: "pairing" });
await runSetupWizardConfigure({
configure: zalouserConfigure,
cfg: {
channels: {
zalouser: {
dmPolicy: "disabled",
accounts: {
work: {
profile: "work",
dmPolicy: "allowlist",
allowFrom: ["123456789"],
},
},
},
},
} as OpenClawConfig,
prompter,
options: { quickstartDefaults: true },
accountOverrides: { zalouser: "work" },
});
expect(
note.mock.calls.some(([message]) =>
String(message).includes("Current: dmPolicy=allowlist, allowFrom=123456789"),
),
).toBe(true);
});
});

View File

@ -1,6 +1,5 @@
import {
createTopLevelChannelDmPolicy,
createTopLevelChannelDmPolicySetter,
addWildcardAllowFrom,
DEFAULT_ACCOUNT_ID,
formatCliCommand,
formatDocsLink,
@ -30,9 +29,6 @@ import {
} from "./zalo-js.js";
const channel = "zalouser" as const;
const setZalouserDmPolicy = createTopLevelChannelDmPolicySetter({
channel,
});
const ZALOUSER_ALLOW_FROM_PLACEHOLDER = "Alice, 123456789, or leave empty to configure later";
const ZALOUSER_GROUPS_PLACEHOLDER = "Family, Work, 123456789, or leave empty for now";
const ZALOUSER_DM_ACCESS_TITLE = "Zalo Personal DM access";
@ -61,6 +57,31 @@ function setZalouserAccountScopedConfig(
}) as OpenClawConfig;
}
function setZalouserDmPolicy(
cfg: OpenClawConfig,
accountId: string,
policy: DmPolicy,
): OpenClawConfig {
const resolvedAccountId = normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID;
const resolved = resolveZalouserAccountSync({ cfg, accountId: resolvedAccountId });
return setZalouserAccountScopedConfig(
cfg,
resolvedAccountId,
{
dmPolicy: policy,
...(policy === "open"
? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) }
: {}),
},
{
dmPolicy: policy,
...(policy === "open"
? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) }
: {}),
},
);
}
function setZalouserGroupPolicy(
cfg: OpenClawConfig,
accountId: string,
@ -189,12 +210,28 @@ async function promptZalouserAllowFrom(params: {
}
}
const zalouserDmPolicy: ChannelSetupDmPolicy = createTopLevelChannelDmPolicy({
const zalouserDmPolicy: ChannelSetupDmPolicy = {
label: "Zalo Personal",
channel,
policyKey: "channels.zalouser.dmPolicy",
allowFromKey: "channels.zalouser.allowFrom",
getCurrent: (cfg) => (cfg.channels?.zalouser?.dmPolicy ?? "pairing") as DmPolicy,
resolveConfigKeys: (_cfg, accountId) =>
accountId && accountId !== DEFAULT_ACCOUNT_ID
? {
policyKey: `channels.zalouser.accounts.${accountId}.dmPolicy`,
allowFromKey: `channels.zalouser.accounts.${accountId}.allowFrom`,
}
: {
policyKey: "channels.zalouser.dmPolicy",
allowFromKey: "channels.zalouser.allowFrom",
},
getCurrent: (cfg, accountId) =>
resolveZalouserAccountSync({
cfg,
accountId: accountId ?? DEFAULT_ACCOUNT_ID,
}).config.dmPolicy ?? "pairing",
setPolicy: (cfg, policy, accountId) =>
setZalouserDmPolicy(cfg as OpenClawConfig, accountId ?? DEFAULT_ACCOUNT_ID, policy),
promptAllowFrom: async ({ cfg, prompter, accountId }) => {
const id =
accountId && normalizeAccountId(accountId)
@ -206,7 +243,7 @@ const zalouserDmPolicy: ChannelSetupDmPolicy = createTopLevelChannelDmPolicy({
accountId: id,
});
},
});
};
async function promptZalouserQuickstartDmPolicy(params: {
cfg: OpenClawConfig;
@ -215,7 +252,7 @@ async function promptZalouserQuickstartDmPolicy(params: {
}): Promise<OpenClawConfig> {
const { cfg, prompter, accountId } = params;
const resolved = resolveZalouserAccountSync({ cfg, accountId });
const existingPolicy = (cfg.channels?.zalouser?.dmPolicy ?? "pairing") as DmPolicy;
const existingPolicy = resolved.config.dmPolicy ?? "pairing";
const existingAllowFrom = resolved.config.allowFrom ?? [];
const existingLabel = existingAllowFrom.length > 0 ? existingAllowFrom.join(", ") : "unset";
@ -251,7 +288,7 @@ async function promptZalouserQuickstartDmPolicy(params: {
accountId,
});
}
return setZalouserDmPolicy(cfg, policy);
return setZalouserDmPolicy(cfg, accountId, policy);
}
export { zalouserSetupAdapter } from "./setup-core.js";