fix: preserve broadcast account metadata checks

This commit is contained in:
joshavant
2026-07-24 23:52:12 -05:00
committed by Josh Avant
parent d35cff5edc
commit 66aa4b2ba7
4 changed files with 38 additions and 5 deletions
+7 -1
View File
@@ -1666,7 +1666,10 @@ describe("message tool secret scoping", () => {
actions: ["send"],
config: {
listAccountIds: () => ["shared"],
resolveAccount: () => ({ enabled: true }),
inspectAccount: () => ({ enabled: true }),
resolveAccount: () => {
throw new Error("unresolved Slack SecretRef");
},
},
});
const telegramPlugin = createChannelPlugin({
@@ -1677,6 +1680,7 @@ describe("message tool secret scoping", () => {
actions: ["send"],
config: {
listAccountIds: () => ["shared"],
isEnabled: () => false,
resolveAccount: () => ({ enabled: false }),
},
});
@@ -1707,6 +1711,8 @@ describe("message tool secret scoping", () => {
mockSendResult({ channel: "slack", to: "channel:ops" });
const tool = createMessageTool({
config: rawConfig as never,
currentChannelProvider: "telegram",
currentChannelId: "channel:current",
getScopedChannelsCommandSecretTargets: mocks.getScopedChannelsCommandSecretTargets as never,
resolveCommandSecretRefsViaGateway: mocks.resolveCommandSecretRefsViaGateway as never,
runMessageAction: mocks.runMessageAction as never,
+11 -3
View File
@@ -1560,6 +1560,12 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
const gatewayOpts = readGatewayCallOptions(params);
const rawConfig = options?.config ?? loadConfigForTool();
const requestedAccountId = readStringParam(params, "accountId");
const requestedScope = resolveMessageSecretScope({
channel: params.channel,
target: params.target,
targets: params.targets,
accountId: requestedAccountId,
});
const scope = resolveMessageSecretScope({
channel: params.channel,
target: params.target,
@@ -1568,9 +1574,11 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
accountId: requestedAccountId,
fallbackAccountId: agentAccountId,
});
const unscopedExplicitBroadcast =
action === "broadcast" && !requestedScope.channel && requestedAccountId !== undefined;
const explicitAccountId = validateExplicitMessageAccountSelection({
cfg: rawConfig,
channel: scope.channel,
channel: unscopedExplicitBroadcast ? undefined : scope.channel,
accountId: requestedAccountId,
checkResolvedAccount: false,
});
@@ -1579,7 +1587,7 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
params.accountId = explicitAccountId;
}
const broadcastAccountPlan =
action === "broadcast" && !scope.channel && explicitAccountId
unscopedExplicitBroadcast && explicitAccountId
? resolveMessageBroadcastAccountPlan({
cfg: rawConfig,
accountId: explicitAccountId,
@@ -1587,7 +1595,7 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
: undefined;
const scopedTargets = getScopedSecretTargetsForTool({
config: rawConfig,
channel: scope.channel,
channel: broadcastAccountPlan ? undefined : scope.channel,
...(broadcastAccountPlan ? { channels: broadcastAccountPlan.secretChannels } : {}),
accountId: scope.accountId,
});
+4 -1
View File
@@ -164,7 +164,10 @@ function createAccountPlugin(id: "slack" | "telegram", accountIds: string[]): Ch
capabilities: { chatTypes: ["direct", "group"], media: true },
config: {
listAccountIds: () => accountIds,
resolveAccount: () => ({ enabled: true }),
inspectAccount: () => ({ enabled: true }),
resolveAccount: () => {
throw new Error("raw account credentials must not resolve during planning");
},
},
};
}
@@ -154,7 +154,23 @@ export function resolveMessageBroadcastAccountPlan(params: {
channel: plugin.id,
accountId,
plugin,
checkResolvedAccount: false,
});
// Prefer the SecretRef-safe metadata view. Legacy plugins without it keep
// their existing resolver contract; a resolver that cannot read refs fails closed.
const accountForEnablement =
plugin.config.inspectAccount?.(params.cfg, accountId) ??
plugin.config.resolveAccount(params.cfg, accountId);
if (
accountForEnablement === undefined ||
!resolveChannelAccountEnabled({
plugin,
account: accountForEnablement,
cfg: params.cfg,
})
) {
throw new Error(`Account "${accountId}" for channel ${plugin.id} is disabled.`);
}
return [plugin.id];
} catch {
return [];