Files
openclaw/extensions/line/src/channel.allowlist.test.ts
Eden 80de877ed3 fix(line): support /allowlist config edits (#106638)
* feat(line): wire base.allowlist config-edit adapter

LINE was the only DM/group channel without a base.allowlist adapter, so
`openclaw allow line` / the /allowlist command replied "does not support"
instead of editing the LINE allowlist. Reuse buildDmGroupAccountAllowlistAdapter
(DM + group + per-group-override scopes), matching Telegram/Signal; entry
normalization flows through the existing lineConfigAdapter.formatAllowFrom.

* fix(allowlist): preserve inherited account entries

* fix(allowlist): preserve all-scope store edits

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>

* test(allowlist): import config type

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>

* fix(allowlist): preserve empty effective overrides

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>

* fix(allowlist): reject group-only store edits

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>

* fix(allowlist): preserve cleared channel overrides

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 03:38:13 -07:00

162 lines
4.7 KiB
TypeScript

// Line tests cover allowlist config-edit adapter plugin behavior.
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import { describe, expect, it } from "vitest";
import { linePlugin } from "./channel.js";
const allowlist = linePlugin.allowlist;
describe("line allowlist adapter", () => {
it("exposes the config-edit contract", () => {
expect(allowlist?.applyConfigEdit).toBeTypeOf("function");
expect(allowlist?.readConfig).toBeTypeOf("function");
expect(allowlist?.supportsScope).toBeTypeOf("function");
});
it.each([
{ scope: "dm", expected: true },
{ scope: "group", expected: true },
{ scope: "all", expected: true },
] as const)("supports the $scope scope", ({ scope, expected }) => {
expect(allowlist?.supportsScope?.({ scope })).toBe(expected);
});
it("reads dm/group allowlists and group overrides from line config", () => {
const cfg = {
channels: {
line: {
enabled: true,
dmPolicy: "allowlist",
groupPolicy: "allowlist",
allowFrom: ["Ualice"],
groupAllowFrom: ["Ubob"],
groups: {
Cgroup1: { allowFrom: ["Ucarol"] },
},
},
},
} as OpenClawConfig;
expect(allowlist?.readConfig?.({ cfg, accountId: "default" })).toEqual({
dmAllowFrom: ["Ualice"],
groupAllowFrom: ["Ubob"],
dmPolicy: "allowlist",
groupPolicy: "allowlist",
groupOverrides: [{ label: "Cgroup1", entries: ["Ucarol"] }],
});
});
it("adds a dm allowlist entry under channels.line.allowFrom", () => {
const parsedConfig: Record<string, unknown> = {};
const result = allowlist?.applyConfigEdit?.({
cfg: {} as OpenClawConfig,
parsedConfig,
accountId: "default",
scope: "dm",
action: "add",
entry: "Udave",
});
expect(result).toEqual({
kind: "ok",
changed: true,
pathLabel: "channels.line.allowFrom",
writeTarget: { kind: "channel", scope: { channelId: "line" } },
});
expect(parsedConfig).toMatchObject({ channels: { line: { allowFrom: ["Udave"] } } });
});
it("adds a dm allowlist entry under the named LINE account", () => {
const parsedConfig: Record<string, unknown> = {
channels: {
line: {
allowFrom: ["Uexisting"],
accounts: {
support: {},
},
},
},
};
const result = allowlist?.applyConfigEdit?.({
cfg: parsedConfig as OpenClawConfig,
parsedConfig,
accountId: "support",
scope: "dm",
action: "add",
entry: "Unew",
});
expect(result).toEqual({
kind: "ok",
changed: true,
pathLabel: "channels.line.accounts.support.allowFrom",
writeTarget: {
kind: "account",
scope: { channelId: "line", accountId: "support" },
},
});
expect(parsedConfig).toMatchObject({
channels: {
line: {
accounts: {
support: { allowFrom: ["Uexisting", "Unew"] },
},
},
},
});
});
it("adds a group allowlist entry under channels.line.groupAllowFrom", () => {
const parsedConfig: Record<string, unknown> = {};
const result = allowlist?.applyConfigEdit?.({
cfg: {} as OpenClawConfig,
parsedConfig,
accountId: "default",
scope: "group",
action: "add",
entry: "Uerin",
});
expect(result).toEqual({
kind: "ok",
changed: true,
pathLabel: "channels.line.groupAllowFrom",
writeTarget: { kind: "channel", scope: { channelId: "line" } },
});
expect(parsedConfig).toMatchObject({ channels: { line: { groupAllowFrom: ["Uerin"] } } });
});
it("treats a line:-prefixed entry as already present via the line normalizer", () => {
const parsedConfig: Record<string, unknown> = {
channels: { line: { allowFrom: ["Ufrank"] } },
};
const result = allowlist?.applyConfigEdit?.({
cfg: {} as OpenClawConfig,
parsedConfig,
accountId: "default",
scope: "dm",
action: "add",
entry: "line:user:Ufrank",
});
expect(result).toMatchObject({ kind: "ok", changed: false });
expect(parsedConfig).toMatchObject({ channels: { line: { allowFrom: ["Ufrank"] } } });
});
it("removes a dm allowlist entry and keeps the rest", () => {
const parsedConfig: Record<string, unknown> = {
channels: { line: { allowFrom: ["Ugone", "Ustay"] } },
};
const result = allowlist?.applyConfigEdit?.({
cfg: {} as OpenClawConfig,
parsedConfig,
accountId: "default",
scope: "dm",
action: "remove",
entry: "Ugone",
});
expect(result).toMatchObject({ kind: "ok", changed: true });
expect(parsedConfig).toMatchObject({ channels: { line: { allowFrom: ["Ustay"] } } });
});
});