mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-30 06:14:23 +00:00
refactor: share plugin directory helpers
This commit is contained in:
@@ -6,6 +6,13 @@ import {
|
||||
listDirectoryUserEntriesFromAllowFrom,
|
||||
} from "./directory-config-helpers.js";
|
||||
|
||||
function expectUserDirectoryEntries(entries: unknown) {
|
||||
expect(entries).toEqual([
|
||||
{ kind: "user", id: "alice" },
|
||||
{ kind: "user", id: "carla" },
|
||||
]);
|
||||
}
|
||||
|
||||
describe("listDirectoryUserEntriesFromAllowFrom", () => {
|
||||
it("normalizes, deduplicates, filters, and limits user ids", () => {
|
||||
const entries = listDirectoryUserEntriesFromAllowFrom({
|
||||
@@ -15,10 +22,7 @@ describe("listDirectoryUserEntriesFromAllowFrom", () => {
|
||||
limit: 2,
|
||||
});
|
||||
|
||||
expect(entries).toEqual([
|
||||
{ kind: "user", id: "alice" },
|
||||
{ kind: "user", id: "carla" },
|
||||
]);
|
||||
expectUserDirectoryEntries(entries);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,10 +58,7 @@ describe("listDirectoryUserEntriesFromAllowFromAndMapKeys", () => {
|
||||
limit: 2,
|
||||
});
|
||||
|
||||
expect(entries).toEqual([
|
||||
{ kind: "user", id: "alice" },
|
||||
{ kind: "user", id: "carla" },
|
||||
]);
|
||||
expectUserDirectoryEntries(entries);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -22,12 +22,12 @@ export function toDirectoryEntries(kind: "user" | "group", ids: string[]): Chann
|
||||
return ids.map((id) => ({ kind, id }) as const);
|
||||
}
|
||||
|
||||
function collectDirectoryIdsFromEntries(params: {
|
||||
entries?: readonly unknown[];
|
||||
function normalizeDirectoryIds(params: {
|
||||
rawIds: readonly string[];
|
||||
normalizeId?: (entry: string) => string | null | undefined;
|
||||
}): string[] {
|
||||
return (params.entries ?? [])
|
||||
.map((entry) => String(entry).trim())
|
||||
return params.rawIds
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => Boolean(entry) && entry !== "*")
|
||||
.map((entry) => {
|
||||
const normalized = params.normalizeId ? params.normalizeId(entry) : entry;
|
||||
@@ -36,18 +36,24 @@ function collectDirectoryIdsFromEntries(params: {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function collectDirectoryIdsFromEntries(params: {
|
||||
entries?: readonly unknown[];
|
||||
normalizeId?: (entry: string) => string | null | undefined;
|
||||
}): string[] {
|
||||
return normalizeDirectoryIds({
|
||||
rawIds: (params.entries ?? []).map((entry) => String(entry)),
|
||||
normalizeId: params.normalizeId,
|
||||
});
|
||||
}
|
||||
|
||||
function collectDirectoryIdsFromMapKeys(params: {
|
||||
groups?: Record<string, unknown>;
|
||||
normalizeId?: (entry: string) => string | null | undefined;
|
||||
}): string[] {
|
||||
return Object.keys(params.groups ?? {})
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => Boolean(entry) && entry !== "*")
|
||||
.map((entry) => {
|
||||
const normalized = params.normalizeId ? params.normalizeId(entry) : entry;
|
||||
return typeof normalized === "string" ? normalized.trim() : "";
|
||||
})
|
||||
.filter(Boolean);
|
||||
return normalizeDirectoryIds({
|
||||
rawIds: Object.keys(params.groups ?? {}),
|
||||
normalizeId: params.normalizeId,
|
||||
});
|
||||
}
|
||||
|
||||
function dedupeDirectoryIds(ids: string[]): string[] {
|
||||
|
||||
@@ -410,33 +410,43 @@ describe("resolveChannelConfigWrites", () => {
|
||||
});
|
||||
|
||||
describe("authorizeConfigWrite", () => {
|
||||
it("blocks when a target account disables writes", () => {
|
||||
const cfg = makeSlackConfigWritesCfg("work");
|
||||
function expectConfigWriteBlocked(params: {
|
||||
disabledAccountId: string;
|
||||
reason: "target-disabled" | "origin-disabled";
|
||||
blockedScope: "target" | "origin";
|
||||
}) {
|
||||
expect(
|
||||
authorizeConfigWrite({
|
||||
cfg,
|
||||
cfg: makeSlackConfigWritesCfg(params.disabledAccountId),
|
||||
origin: { channelId: "slack", accountId: "default" },
|
||||
target: resolveExplicitConfigWriteTarget({ channelId: "slack", accountId: "work" }),
|
||||
}),
|
||||
).toEqual({
|
||||
allowed: false,
|
||||
reason: params.reason,
|
||||
blockedScope: {
|
||||
kind: params.blockedScope,
|
||||
scope: {
|
||||
channelId: "slack",
|
||||
accountId: params.blockedScope === "target" ? "work" : "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
it("blocks when a target account disables writes", () => {
|
||||
expectConfigWriteBlocked({
|
||||
disabledAccountId: "work",
|
||||
reason: "target-disabled",
|
||||
blockedScope: { kind: "target", scope: { channelId: "slack", accountId: "work" } },
|
||||
blockedScope: "target",
|
||||
});
|
||||
});
|
||||
|
||||
it("blocks when the origin account disables writes", () => {
|
||||
const cfg = makeSlackConfigWritesCfg("default");
|
||||
expect(
|
||||
authorizeConfigWrite({
|
||||
cfg,
|
||||
origin: { channelId: "slack", accountId: "default" },
|
||||
target: resolveExplicitConfigWriteTarget({ channelId: "slack", accountId: "work" }),
|
||||
}),
|
||||
).toEqual({
|
||||
allowed: false,
|
||||
expectConfigWriteBlocked({
|
||||
disabledAccountId: "default",
|
||||
reason: "origin-disabled",
|
||||
blockedScope: { kind: "origin", scope: { channelId: "slack", accountId: "default" } },
|
||||
blockedScope: "origin",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -41,6 +41,19 @@ async function buildSnapshotFromAccount<ResolvedAccount>(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function inspectChannelAccount<ResolvedAccount>(params: {
|
||||
plugin: ChannelPlugin<ResolvedAccount>;
|
||||
cfg: OpenClawConfig;
|
||||
accountId: string;
|
||||
}): ResolvedAccount | null {
|
||||
return (params.plugin.config.inspectAccount?.(params.cfg, params.accountId) ??
|
||||
inspectReadOnlyChannelAccount({
|
||||
channelId: params.plugin.id,
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
})) as ResolvedAccount | null;
|
||||
}
|
||||
|
||||
export async function buildReadOnlySourceChannelAccountSnapshot<ResolvedAccount>(params: {
|
||||
plugin: ChannelPlugin<ResolvedAccount>;
|
||||
cfg: OpenClawConfig;
|
||||
@@ -49,13 +62,7 @@ export async function buildReadOnlySourceChannelAccountSnapshot<ResolvedAccount>
|
||||
probe?: unknown;
|
||||
audit?: unknown;
|
||||
}): Promise<ChannelAccountSnapshot | null> {
|
||||
const inspectedAccount =
|
||||
params.plugin.config.inspectAccount?.(params.cfg, params.accountId) ??
|
||||
inspectReadOnlyChannelAccount({
|
||||
channelId: params.plugin.id,
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
const inspectedAccount = inspectChannelAccount(params);
|
||||
if (!inspectedAccount) {
|
||||
return null;
|
||||
}
|
||||
@@ -73,15 +80,9 @@ export async function buildChannelAccountSnapshot<ResolvedAccount>(params: {
|
||||
probe?: unknown;
|
||||
audit?: unknown;
|
||||
}): Promise<ChannelAccountSnapshot> {
|
||||
const inspectedAccount =
|
||||
params.plugin.config.inspectAccount?.(params.cfg, params.accountId) ??
|
||||
inspectReadOnlyChannelAccount({
|
||||
channelId: params.plugin.id,
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
const account = (inspectedAccount ??
|
||||
params.plugin.config.resolveAccount(params.cfg, params.accountId)) as ResolvedAccount;
|
||||
const inspectedAccount = inspectChannelAccount(params);
|
||||
const account =
|
||||
inspectedAccount ?? params.plugin.config.resolveAccount(params.cfg, params.accountId);
|
||||
return await buildSnapshotFromAccount({
|
||||
...params,
|
||||
account,
|
||||
|
||||
Reference in New Issue
Block a user