mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-20 19:21:39 +00:00
fix(outbound): preserve configured directory entries before reserved-literal rejection in resolveMessagingTarget
Move the reserved-literal check from before directory lookup to after directory miss, so configured Telegram groups/channels whose directory key is a reserved word (current, self, this, me) still resolve through the directory before failing closed. The reserved check now runs only after the directory returns no match and before plugin fallback resolution. Update the regression test to verify directory-first ordering: a configured directory entry named current resolves successfully, and a directory miss with a reserved literal fails with the descriptive error.
This commit is contained in:
committed by
Ayaan Zaidi
parent
f12ade0082
commit
bbf494955d
@@ -130,7 +130,7 @@ describe("resolveMessagingTarget (directory fallback)", () => {
|
||||
expect(mocks.listGroupsLive).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("rejects plugin-reserved literal targets before directory lookup", async () => {
|
||||
it("preserves configured directory entries before rejecting reserved literal targets", async () => {
|
||||
mocks.getChannelPlugin.mockReturnValue({
|
||||
...createChannelTestPluginBase({ id: "telegram", label: "Telegram" }),
|
||||
directory: {
|
||||
@@ -162,13 +162,47 @@ describe("resolveMessagingTarget (directory fallback)", () => {
|
||||
input: "current",
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
if (result.ok) {
|
||||
expect(result.target.to).toBe("-1002458651455");
|
||||
expect(result.target.source).toBe("directory");
|
||||
}
|
||||
expect(mocks.listGroups).toHaveBeenCalled();
|
||||
expect(mocks.resolveTarget).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects reserved literal targets after directory miss", async () => {
|
||||
mocks.getChannelPlugin.mockReturnValue({
|
||||
...createChannelTestPluginBase({ id: "telegram", label: "Telegram" }),
|
||||
directory: {
|
||||
listPeers: mocks.listPeers,
|
||||
listPeersLive: mocks.listPeersLive,
|
||||
listGroups: mocks.listGroups,
|
||||
listGroupsLive: mocks.listGroupsLive,
|
||||
},
|
||||
messaging: {
|
||||
targetResolver: {
|
||||
reservedLiterals: ["current", "self", "this", "me"],
|
||||
hint: "<chatId>",
|
||||
resolveTarget: mocks.resolveTarget,
|
||||
},
|
||||
},
|
||||
});
|
||||
mocks.listGroups.mockResolvedValue([]);
|
||||
mocks.listGroupsLive.mockResolvedValue([]);
|
||||
|
||||
const result = await resolveMessagingTarget({
|
||||
cfg,
|
||||
channel: "telegram",
|
||||
input: "current",
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
expect(result.error.message).toContain('Reserved target "current"');
|
||||
expect(result.error.message).toContain("Telegram");
|
||||
}
|
||||
expect(mocks.listGroups).not.toHaveBeenCalled();
|
||||
expect(mocks.listGroupsLive).not.toHaveBeenCalled();
|
||||
expect(mocks.listGroups).toHaveBeenCalled();
|
||||
expect(mocks.resolveTarget).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -400,10 +400,6 @@ export async function resolveMessagingTarget(params: {
|
||||
const plugin = params.plugin ?? getChannelPlugin(params.channel);
|
||||
const providerLabel = plugin?.meta?.label ?? params.channel;
|
||||
const hint = plugin?.messaging?.targetResolver?.hint;
|
||||
const reservedLiteral = resolveReservedTargetLiteral({ raw, plugin });
|
||||
if (reservedLiteral) {
|
||||
return { ok: false, error: reservedTargetLiteralError(providerLabel, reservedLiteral, hint) };
|
||||
}
|
||||
const kind = detectTargetKind(params.channel, raw, params.preferredKind, plugin);
|
||||
const normalizedInput = resolveNormalizedTargetInput(params.channel, raw, plugin);
|
||||
const normalized = normalizedInput?.normalized ?? raw;
|
||||
@@ -483,6 +479,13 @@ export async function resolveMessagingTarget(params: {
|
||||
candidates: match.entries,
|
||||
};
|
||||
}
|
||||
// Directory miss: reject reserved literals before falling back to plugin
|
||||
// resolution, so a bare reserved word without a matching directory entry
|
||||
// does not accidentally resolve to a public channel or incorrect target.
|
||||
const reservedLiteral = resolveReservedTargetLiteral({ raw, plugin });
|
||||
if (reservedLiteral) {
|
||||
return { ok: false, error: reservedTargetLiteralError(providerLabel, reservedLiteral, hint) };
|
||||
}
|
||||
const resolvedFallbackTarget = asResolvedMessagingTarget(
|
||||
await maybeResolvePluginMessagingTarget({
|
||||
cfg: params.cfg,
|
||||
|
||||
Reference in New Issue
Block a user