Skip to content

Commit 17c1ee7

Browse files
committed
fix: preserve command auth resolution errors on empty inferred allowlists
1 parent 630f147 commit 17c1ee7

File tree

2 files changed

+61
-9
lines changed

2 files changed

+61
-9
lines changed

src/auto-reply/command-auth.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,9 @@ function resolveProviderFromContext(
6969
accountId: ctx.AccountId,
7070
allowFrom: resolvedAllowFrom.allowFrom,
7171
});
72-
if (allowFrom.length === 0) {
73-
return null;
74-
}
7572
return {
7673
providerId: plugin.id,
74+
allowFrom,
7775
hadResolutionError: resolvedAllowFrom.hadResolutionError,
7876
};
7977
})
@@ -82,11 +80,16 @@ function resolveProviderFromContext(
8280
value,
8381
): value is {
8482
providerId: ChannelId;
83+
allowFrom: string[];
8584
hadResolutionError: boolean;
8685
} => Boolean(value),
8786
);
88-
if (configured.length === 1) {
89-
return configured[0];
87+
const inferred = configured.filter((entry) => entry.allowFrom.length > 0);
88+
if (inferred.length === 1) {
89+
return {
90+
providerId: inferred[0].providerId,
91+
hadResolutionError: inferred[0].hadResolutionError,
92+
};
9093
}
9194
return {
9295
providerId: undefined,
@@ -450,6 +453,9 @@ export function resolveCommandAuthorization(params: {
450453
const plugin = providerId ? getChannelPlugin(providerId) : undefined;
451454
const from = (ctx.From ?? "").trim();
452455
const to = (ctx.To ?? "").trim();
456+
const commandsAllowFromConfigured = Boolean(
457+
cfg.commands?.allowFrom && typeof cfg.commands.allowFrom === "object",
458+
);
453459

454460
// Check if commands.allowFrom is configured (separate command authorization)
455461
const commandsAllowFromList = resolveCommandsAllowFromList({
@@ -565,10 +571,12 @@ export function resolveCommandAuthorization(params: {
565571
// If commands.allowFrom is configured, use it for command authorization
566572
// Otherwise, fall back to existing behavior (channel allowFrom + owner checks)
567573
let isAuthorizedSender: boolean;
568-
if (commandsAllowFromList !== null) {
574+
if (commandsAllowFromList !== null || (providerResolutionError && commandsAllowFromConfigured)) {
569575
// commands.allowFrom is configured - use it for authorization
570-
const commandsAllowAll = commandsAllowFromList.some((entry) => entry.trim() === "*");
571-
const matchedCommandsAllowFrom = commandsAllowFromList.length
576+
const commandsAllowAll =
577+
!providerResolutionError &&
578+
Boolean(commandsAllowFromList?.some((entry) => entry.trim() === "*"));
579+
const matchedCommandsAllowFrom = commandsAllowFromList?.length
572580
? senderCandidates.find((candidate) => commandsAllowFromList.includes(candidate))
573581
: undefined;
574582
isAuthorizedSender =

src/auto-reply/command-control.test.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,6 @@ describe("resolveCommandAuthorization", () => {
487487

488488
expect(deniedAuth.isAuthorizedSender).toBe(false);
489489
});
490-
491490
it("fails closed when provider inference hits unresolved SecretRef allowlists", () => {
492491
setActivePluginRegistry(
493492
createTestRegistry([
@@ -538,6 +537,51 @@ describe("resolveCommandAuthorization", () => {
538537
expect(auth.isAuthorizedSender).toBe(false);
539538
});
540539

540+
it("preserves provider resolution errors when inferred fallback allowFrom is empty", () => {
541+
setActivePluginRegistry(
542+
createTestRegistry([
543+
{
544+
pluginId: "telegram",
545+
plugin: {
546+
...createOutboundTestPlugin({
547+
id: "telegram",
548+
outbound: { deliveryMode: "direct" },
549+
}),
550+
config: {
551+
listAccountIds: () => ["default"],
552+
resolveAccount: () => ({}),
553+
resolveAllowFrom: () => {
554+
throw new Error("channels.telegram.botToken: unresolved SecretRef");
555+
},
556+
formatAllowFrom: ({ allowFrom }: { allowFrom: Array<string | number> }) =>
557+
allowFrom.map((entry) => String(entry).trim()).filter(Boolean),
558+
},
559+
},
560+
source: "test",
561+
},
562+
]),
563+
);
564+
565+
const auth = resolveCommandAuthorization({
566+
ctx: {
567+
SenderId: "123",
568+
} as MsgContext,
569+
cfg: {
570+
commands: {
571+
allowFrom: {
572+
telegram: ["123"],
573+
},
574+
},
575+
channels: {
576+
telegram: {},
577+
},
578+
} as OpenClawConfig,
579+
commandAuthorized: true,
580+
});
581+
582+
expect(auth.providerId).toBeUndefined();
583+
expect(auth.isAuthorizedSender).toBe(false);
584+
});
541585
it("does not let an unrelated provider resolution error poison inferred commands.allowFrom", () => {
542586
setActivePluginRegistry(
543587
createTestRegistry([

0 commit comments

Comments
 (0)