feat(security): integrate secret detection into message dispatch

This commit is contained in:
Rome Thorstenson 2026-01-30 07:25:48 -08:00
parent 83bca1871b
commit 64be499d96

View File

@ -11,6 +11,13 @@ import {
type ReplyDispatcherOptions,
type ReplyDispatcherWithTypingOptions,
} from "./reply/reply-dispatcher.js";
import { processSecretsInMessage } from "../security/process-secrets.js";
import {
generatePromptKey,
hasPendingPrompt,
resolvePendingPrompt,
parsePromptResponse,
} from "../security/interactive-prompts.js";
export type DispatchInboundResult = DispatchFromConfigResult;
@ -22,8 +29,52 @@ export async function dispatchInboundMessage(params: {
replyResolver?: typeof import("./reply.js").getReplyFromConfig;
}): Promise<DispatchInboundResult> {
const finalized = finalizeInboundContext(params.ctx);
// Check if this user has a pending security prompt
const channel = finalized.Provider || finalized.Surface || 'unknown';
const senderId = finalized.SenderId || 'unknown';
const promptKey = generatePromptKey(channel, senderId);
if (hasPendingPrompt(promptKey)) {
// This message is a response to a security prompt
const body = finalized.Body || '';
const parsedAction = parsePromptResponse(body);
if (parsedAction) {
// Valid response - resolve the pending prompt
resolvePendingPrompt(promptKey, parsedAction);
// Send confirmation
await params.dispatcher.sendText(`✓ Applying action: ${parsedAction}`);
} else {
// Invalid response - send help message and keep the prompt pending
await params.dispatcher.sendText(
`❌ Invalid response. Please reply with **1**, **2**, **3**, or **4**.`,
);
}
// Don't process this message further
return {
handled: true,
replies: [],
errors: [],
};
}
// Process secrets before dispatching to agent
const secretProcessing = await processSecretsInMessage(finalized, params.cfg, params.dispatcher);
// If the message was blocked by the user (cancelled), don't proceed
if (secretProcessing.blocked) {
return {
handled: true,
replies: [],
errors: [],
};
}
// Use the updated context (with redacted/replaced secrets if applicable)
return await dispatchReplyFromConfig({
ctx: finalized,
ctx: secretProcessing.ctx,
cfg: params.cfg,
dispatcher: params.dispatcher,
replyOptions: params.replyOptions,