mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 08:47:40 +00:00
fix(discord): enrich allowlist resolution logs
This commit is contained in:
@@ -2,7 +2,9 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../../runtime.js";
|
||||
|
||||
const { resolveDiscordChannelAllowlistMock, resolveDiscordUserAllowlistMock } = vi.hoisted(() => ({
|
||||
resolveDiscordChannelAllowlistMock: vi.fn(async () => []),
|
||||
resolveDiscordChannelAllowlistMock: vi.fn(
|
||||
async (_params: { entries: string[] }) => [] as Array<Record<string, unknown>>,
|
||||
),
|
||||
resolveDiscordUserAllowlistMock: vi.fn(async (params: { entries: string[] }) =>
|
||||
params.entries.map((entry) => {
|
||||
switch (entry) {
|
||||
@@ -12,6 +14,8 @@ const { resolveDiscordChannelAllowlistMock, resolveDiscordUserAllowlistMock } =
|
||||
return { input: entry, resolved: true, id: "222" };
|
||||
case "Carol":
|
||||
return { input: entry, resolved: false };
|
||||
case "387":
|
||||
return { input: entry, resolved: true, id: "387", name: "Peter" };
|
||||
default:
|
||||
return { input: entry, resolved: true, id: entry };
|
||||
}
|
||||
@@ -54,4 +58,39 @@ describe("resolveDiscordAllowlistConfig", () => {
|
||||
expect(result.guildEntries?.["*"]?.channels?.["*"]?.users).toEqual(["Carol", "888"]);
|
||||
expect(resolveDiscordUserAllowlistMock).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("logs discord name metadata for resolved and unresolved allowlist entries", async () => {
|
||||
resolveDiscordChannelAllowlistMock.mockResolvedValueOnce([
|
||||
{
|
||||
input: "145/c404",
|
||||
resolved: false,
|
||||
guildId: "145",
|
||||
guildName: "Ops",
|
||||
channelName: "missing-room",
|
||||
},
|
||||
]);
|
||||
const runtime = { log: vi.fn(), error: vi.fn(), exit: vi.fn() } as unknown as RuntimeEnv;
|
||||
|
||||
await resolveDiscordAllowlistConfig({
|
||||
token: "token",
|
||||
allowFrom: ["387"],
|
||||
guildEntries: {
|
||||
"145": {
|
||||
channels: {
|
||||
c404: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
fetcher: vi.fn() as unknown as typeof fetch,
|
||||
runtime,
|
||||
});
|
||||
|
||||
const logs = (runtime.log as ReturnType<typeof vi.fn>).mock.calls
|
||||
.map(([line]) => String(line))
|
||||
.join("\n");
|
||||
expect(logs).toContain(
|
||||
"discord channels unresolved: 145/c404 (guild:Ops; channel:missing-room)",
|
||||
);
|
||||
expect(logs).toContain("discord users resolved: 387→387 (name:Peter)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,71 @@ import { resolveDiscordUserAllowlist } from "../resolve-users.js";
|
||||
|
||||
type GuildEntries = Record<string, DiscordGuildEntry>;
|
||||
type ChannelResolutionInput = { input: string; guildKey: string; channelKey?: string };
|
||||
type DiscordChannelLogEntry = {
|
||||
input: string;
|
||||
guildId?: string;
|
||||
guildName?: string;
|
||||
channelId?: string;
|
||||
channelName?: string;
|
||||
note?: string;
|
||||
};
|
||||
type DiscordUserLogEntry = {
|
||||
input: string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
guildName?: string;
|
||||
note?: string;
|
||||
};
|
||||
|
||||
function formatResolutionLogDetails(base: string, details: Array<string | undefined>): string {
|
||||
const nonEmpty = details
|
||||
.map((value) => value?.trim())
|
||||
.filter((value): value is string => Boolean(value));
|
||||
return nonEmpty.length > 0 ? `${base} (${nonEmpty.join("; ")})` : base;
|
||||
}
|
||||
|
||||
function formatDiscordChannelResolved(entry: DiscordChannelLogEntry): string {
|
||||
const target = entry.channelId ? `${entry.guildId}/${entry.channelId}` : entry.guildId;
|
||||
const base = `${entry.input}→${target}`;
|
||||
return formatResolutionLogDetails(base, [
|
||||
entry.guildName ? `guild:${entry.guildName}` : undefined,
|
||||
entry.channelName ? `channel:${entry.channelName}` : undefined,
|
||||
entry.note,
|
||||
]);
|
||||
}
|
||||
|
||||
function formatDiscordChannelUnresolved(entry: DiscordChannelLogEntry): string {
|
||||
return formatResolutionLogDetails(entry.input, [
|
||||
entry.guildName
|
||||
? `guild:${entry.guildName}`
|
||||
: entry.guildId
|
||||
? `guildId:${entry.guildId}`
|
||||
: undefined,
|
||||
entry.channelName
|
||||
? `channel:${entry.channelName}`
|
||||
: entry.channelId
|
||||
? `channelId:${entry.channelId}`
|
||||
: undefined,
|
||||
entry.note,
|
||||
]);
|
||||
}
|
||||
|
||||
function formatDiscordUserResolved(entry: DiscordUserLogEntry): string {
|
||||
const base = `${entry.input}→${entry.id}`;
|
||||
return formatResolutionLogDetails(base, [
|
||||
entry.name ? `name:${entry.name}` : undefined,
|
||||
entry.guildName ? `guild:${entry.guildName}` : undefined,
|
||||
entry.note,
|
||||
]);
|
||||
}
|
||||
|
||||
function formatDiscordUserUnresolved(entry: DiscordUserLogEntry): string {
|
||||
return formatResolutionLogDetails(entry.input, [
|
||||
entry.name ? `name:${entry.name}` : undefined,
|
||||
entry.guildName ? `guild:${entry.guildName}` : undefined,
|
||||
entry.note,
|
||||
]);
|
||||
}
|
||||
|
||||
function toGuildEntries(value: unknown): GuildEntries {
|
||||
if (!value || typeof value !== "object") {
|
||||
@@ -90,14 +155,10 @@ async function resolveGuildEntriesByChannelAllowlist(params: {
|
||||
}
|
||||
const sourceGuild = params.guildEntries[source.guildKey] ?? {};
|
||||
if (!entry.resolved || !entry.guildId) {
|
||||
unresolved.push(entry.input);
|
||||
unresolved.push(formatDiscordChannelUnresolved(entry));
|
||||
continue;
|
||||
}
|
||||
mapping.push(
|
||||
entry.channelId
|
||||
? `${entry.input}→${entry.guildId}/${entry.channelId}`
|
||||
: `${entry.input}→${entry.guildId}`,
|
||||
);
|
||||
mapping.push(formatDiscordChannelResolved(entry));
|
||||
const existing = nextGuilds[entry.guildId] ?? {};
|
||||
const mergedChannels = {
|
||||
...sourceGuild.channels,
|
||||
@@ -153,7 +214,10 @@ async function resolveAllowFromByUserAllowlist(params: {
|
||||
entries: allowEntries.map((entry) => String(entry)),
|
||||
fetcher: params.fetcher,
|
||||
});
|
||||
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
||||
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers, {
|
||||
formatResolved: formatDiscordUserResolved,
|
||||
formatUnresolved: formatDiscordUserUnresolved,
|
||||
});
|
||||
const allowFrom = canonicalizeAllowlistWithResolvedIds({
|
||||
existing: params.allowFrom,
|
||||
resolvedMap,
|
||||
@@ -199,7 +263,10 @@ async function resolveGuildEntriesByUserAllowlist(params: {
|
||||
entries: Array.from(userEntries),
|
||||
fetcher: params.fetcher,
|
||||
});
|
||||
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers);
|
||||
const { resolvedMap, mapping, unresolved } = buildAllowlistResolutionSummary(resolvedUsers, {
|
||||
formatResolved: formatDiscordUserResolved,
|
||||
formatUnresolved: formatDiscordUserUnresolved,
|
||||
});
|
||||
const nextGuilds = { ...params.guildEntries };
|
||||
for (const [guildKey, guildConfig] of Object.entries(params.guildEntries)) {
|
||||
if (!guildConfig || typeof guildConfig !== "object") {
|
||||
|
||||
@@ -549,6 +549,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
const logger = createSubsystemLogger("discord/monitor");
|
||||
const guildHistories = new Map<string, HistoryEntry[]>();
|
||||
let botUserId: string | undefined;
|
||||
let botUserName: string | undefined;
|
||||
let voiceManager: DiscordVoiceManager | null = null;
|
||||
|
||||
if (nativeDisabledExplicit) {
|
||||
@@ -562,6 +563,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
try {
|
||||
const botUser = await client.fetchUser("@me");
|
||||
botUserId = botUser?.id;
|
||||
botUserName = botUser?.username?.trim() || botUser?.globalName?.trim() || undefined;
|
||||
} catch (err) {
|
||||
runtime.error?.(danger(`discord: failed to fetch bot identity: ${String(err)}`));
|
||||
}
|
||||
@@ -657,7 +659,9 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
runtime.log?.("discord: GuildPresences intent enabled — presence listener registered");
|
||||
}
|
||||
|
||||
runtime.log?.(`logged in to discord${botUserId ? ` as ${botUserId}` : ""}`);
|
||||
const botIdentity =
|
||||
botUserId && botUserName ? `${botUserId} (${botUserName})` : (botUserId ?? botUserName ?? "");
|
||||
runtime.log?.(`logged in to discord${botIdentity ? ` as ${botIdentity}` : ""}`);
|
||||
|
||||
lifecycleStarted = true;
|
||||
await runDiscordGatewayLifecycle({
|
||||
|
||||
Reference in New Issue
Block a user