feat: add PrivacyCheckValidator to centralize user prompt privacy checks

- Introduced PrivacyCheckValidator class to encapsulate logic for checking if user prompts are private.
- Updated SessionRoutes to utilize PrivacyCheckValidator for determining prompt privacy during observation and summarization operations.
- Removed duplicate privacy check logic from SessionRoutes, improving code maintainability and readability.
This commit is contained in:
Alex Newman
2025-12-07 22:38:51 -05:00
parent 54c53fda04
commit b9814e87f4
3 changed files with 106 additions and 60 deletions
@@ -16,6 +16,7 @@ import type { WorkerService } from '../../../worker-service.js';
import { BaseRouteHandler } from '../BaseRouteHandler.js';
import { SessionEventBroadcaster } from '../../events/SessionEventBroadcaster.js';
import { SessionCompletionHandler } from '../../session/SessionCompletionHandler.js';
import { PrivacyCheckValidator } from '../../validation/PrivacyCheckValidator.js';
export class SessionRoutes extends BaseRouteHandler {
private completionHandler: SessionCompletionHandler;
@@ -266,13 +267,15 @@ export class SessionRoutes extends BaseRouteHandler {
const promptNumber = store.getPromptCounter(sessionDbId);
// Privacy check: skip if user prompt was entirely private
const userPrompt = store.getUserPrompt(claudeSessionId, promptNumber);
if (!userPrompt || userPrompt.trim() === '') {
logger.debug('HOOK', 'Skipping observation - user prompt was entirely private', {
sessionId: sessionDbId,
promptNumber,
tool_name
});
const userPrompt = PrivacyCheckValidator.checkUserPromptPrivacy(
store,
claudeSessionId,
promptNumber,
'observation',
sessionDbId,
{ tool_name }
);
if (!userPrompt) {
res.json({ status: 'skipped', reason: 'private' });
return;
}
@@ -336,12 +339,14 @@ export class SessionRoutes extends BaseRouteHandler {
const promptNumber = store.getPromptCounter(sessionDbId);
// Privacy check: skip if user prompt was entirely private
const userPrompt = store.getUserPrompt(claudeSessionId, promptNumber);
if (!userPrompt || userPrompt.trim() === '') {
logger.debug('HOOK', 'Skipping summary - user prompt was entirely private', {
sessionId: sessionDbId,
promptNumber
});
const userPrompt = PrivacyCheckValidator.checkUserPromptPrivacy(
store,
claudeSessionId,
promptNumber,
'summarize',
sessionDbId
);
if (!userPrompt) {
res.json({ status: 'skipped', reason: 'private' });
return;
}
@@ -0,0 +1,41 @@
import { SessionStore } from '../../sqlite/SessionStore.js';
import { logger } from '../../../utils/logger.js';
/**
* Validates user prompt privacy for session operations
*
* Centralizes privacy checks to avoid duplicate validation logic across route handlers.
* If user prompt was entirely private (stripped to empty string), we skip processing.
*/
export class PrivacyCheckValidator {
/**
* Check if user prompt is public (not entirely private)
*
* @param store - SessionStore instance
* @param claudeSessionId - Claude session ID
* @param promptNumber - Prompt number within session
* @param operationType - Type of operation being validated ('observation' or 'summarize')
* @returns User prompt text if public, null if private
*/
static checkUserPromptPrivacy(
store: SessionStore,
claudeSessionId: string,
promptNumber: number,
operationType: 'observation' | 'summarize',
sessionDbId: number,
additionalContext?: Record<string, any>
): string | null {
const userPrompt = store.getUserPrompt(claudeSessionId, promptNumber);
if (!userPrompt || userPrompt.trim() === '') {
logger.debug('HOOK', `Skipping ${operationType} - user prompt was entirely private`, {
sessionId: sessionDbId,
promptNumber,
...additionalContext
});
return null;
}
return userPrompt;
}
}