From: Stefan Gasser Date: Sun, 28 Jun 2026 18:59:54 +0000 (+0200) Subject: Move privacy helpers into domain modules (#125) X-Git-Tag: v0.7.3~5 X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=b63c48b64e366e356b7aac226b98b286bd77fd80;p=sgasser-llm-shield.git Move privacy helpers into domain modules (#125) --- diff --git a/AGENTS.md b/AGENTS.md index de47751..dea3b52 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,5 +48,5 @@ Primary endpoints: - `src/routes/` contains HTTP route handlers. - `src/providers/` contains provider clients and stream transformers. - `src/masking/extractors/` contains provider-specific text extraction and insertion. -- `src/services/logger.ts` owns SQLite dashboard logging. +- `src/logging/logger.ts` owns SQLite dashboard logging. - `docs/mint.json` registers API reference docs. diff --git a/src/index.ts b/src/index.ts index 27be078..9614309 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import { createMiddleware } from "hono/factory"; import { HTTPException } from "hono/http-exception"; import { logger } from "hono/logger"; import { getConfig } from "./config"; +import { getLogger } from "./logging/logger"; import { getPIIDetector } from "./pii/detect"; import { anthropicRoutes } from "./routes/anthropic"; import { apiRoutes } from "./routes/api"; @@ -12,7 +13,6 @@ import { dashboardRoutes } from "./routes/dashboard"; import { healthRoutes } from "./routes/health"; import { infoRoutes } from "./routes/info"; import { openaiRoutes } from "./routes/openai"; -import { getLogger } from "./services/logger"; type Variables = { requestId: string; diff --git a/src/services/log-content.test.ts b/src/logging/log-content.test.ts similarity index 100% rename from src/services/log-content.test.ts rename to src/logging/log-content.test.ts diff --git a/src/services/log-content.ts b/src/logging/log-content.ts similarity index 100% rename from src/services/log-content.ts rename to src/logging/log-content.ts diff --git a/src/services/logger.test.ts b/src/logging/logger.test.ts similarity index 100% rename from src/services/logger.test.ts rename to src/logging/logger.test.ts diff --git a/src/services/logger.ts b/src/logging/logger.ts similarity index 100% rename from src/services/logger.ts rename to src/logging/logger.ts diff --git a/src/services/pii.ts b/src/pii/request.ts similarity index 84% rename from src/services/pii.ts rename to src/pii/request.ts index d042e55..a93e620 100644 --- a/src/services/pii.ts +++ b/src/pii/request.ts @@ -1,11 +1,11 @@ /** - * PII Service - detect and mask PII in requests + * PII request helpers - detect and mask PII in requests */ import type { PlaceholderContext } from "../masking/context"; import type { RequestExtractor } from "../masking/types"; -import { getPIIDetector, type PIIDetectionResult } from "../pii/detect"; -import { createMaskingContext, maskRequest } from "../pii/mask"; +import { getPIIDetector, type PIIDetectionResult } from "./detect"; +import { createMaskingContext, maskRequest } from "./mask"; export interface PIIDetectResult { detection: PIIDetectionResult; @@ -60,8 +60,8 @@ export function maskPII( } export type { PlaceholderContext } from "../masking/context"; -export type { PIIDetectionResult, PIIEntity } from "../pii/detect"; -export { createMaskingContext } from "../pii/mask"; +export type { PIIDetectionResult, PIIEntity } from "./detect"; +export { createMaskingContext } from "./mask"; /** * Check if the detector is healthy diff --git a/src/services/privacy-pipeline.test.ts b/src/privacy/pipeline.test.ts similarity index 97% rename from src/services/privacy-pipeline.test.ts rename to src/privacy/pipeline.test.ts index 6b9ee1b..5fb1996 100644 --- a/src/services/privacy-pipeline.test.ts +++ b/src/privacy/pipeline.test.ts @@ -2,7 +2,7 @@ import { afterEach, describe, expect, mock, test } from "bun:test"; import { openaiExtractor } from "../masking/extractors/openai"; import type { PIIDetectionResult } from "../pii/detect"; import type { OpenAIRequest } from "../providers/openai/types"; -import type { PrivacyPipelineConfig } from "./privacy-pipeline"; +import type { PrivacyPipelineConfig } from "./pipeline"; const sampleSecret = "sk-proj-abc123def456ghi789jkl012mno345pqr678stu901vwx"; @@ -29,9 +29,7 @@ mock.module("../pii/detect", () => ({ }), })); -const { PrivacyPipelineDetectionError, processPrivacyPipeline } = await import( - "./privacy-pipeline" -); +const { PrivacyPipelineDetectionError, processPrivacyPipeline } = await import("./pipeline"); const baseConfig: PrivacyPipelineConfig = { mode: "mask", diff --git a/src/services/privacy-pipeline.ts b/src/privacy/pipeline.ts similarity index 91% rename from src/services/privacy-pipeline.ts rename to src/privacy/pipeline.ts index 2b469ec..5aaddf8 100644 --- a/src/services/privacy-pipeline.ts +++ b/src/privacy/pipeline.ts @@ -1,8 +1,12 @@ import type { Config } from "../config"; import type { PlaceholderContext } from "../masking/context"; import type { RequestExtractor } from "../masking/types"; -import { detectPII, maskPII, type PIIDetectResult } from "./pii"; -import { processSecretsRequest, type SecretsProcessResult, secretPlaceholders } from "./secrets"; +import { detectPII, maskPII, type PIIDetectResult } from "../pii/request"; +import { + processSecretsRequest, + type SecretsProcessResult, + secretPlaceholders, +} from "../secrets/request"; export type PrivacyPipelineConfig = Pick; diff --git a/src/routes/anthropic.ts b/src/routes/anthropic.ts index 580a575..19853f3 100644 --- a/src/routes/anthropic.ts +++ b/src/routes/anthropic.ts @@ -2,9 +2,17 @@ import { zValidator } from "@hono/zod-validator"; import type { Context } from "hono"; import { Hono } from "hono"; import { getConfig } from "../config"; +import { formatMaskedRequestForLog } from "../logging/log-content"; +import { logRequest } from "../logging/logger"; import type { PlaceholderContext } from "../masking/context"; import { anthropicExtractor } from "../masking/extractors/anthropic"; import { restoreResponse } from "../masking/restorer"; +import type { PIIDetectResult } from "../pii/request"; +import { + PrivacyPipelineDetectionError, + type PrivacyPipelineResult, + processPrivacyPipeline, +} from "../privacy/pipeline"; import { callAnthropic } from "../providers/anthropic/client"; import { createAnthropicUnmaskingStream } from "../providers/anthropic/stream-transformer"; import { @@ -13,15 +21,7 @@ import { type AnthropicResponse, } from "../providers/anthropic/types"; import { callLocalAnthropic } from "../providers/local"; -import { formatMaskedRequestForLog } from "../services/log-content"; -import { logRequest } from "../services/logger"; -import type { PIIDetectResult } from "../services/pii"; -import { - PrivacyPipelineDetectionError, - type PrivacyPipelineResult, - processPrivacyPipeline, -} from "../services/privacy-pipeline"; -import type { SecretsProcessResult } from "../services/secrets"; +import type { SecretsProcessResult } from "../secrets/request"; import { createLogData, errorFormats, diff --git a/src/routes/api.test.ts b/src/routes/api.test.ts index f9e3199..b291e24 100644 --- a/src/routes/api.test.ts +++ b/src/routes/api.test.ts @@ -20,7 +20,7 @@ mock.module("../pii/detect", () => ({ })); // Mock the logger to avoid database operations -mock.module("../services/logger", () => ({ +mock.module("../logging/logger", () => ({ logRequest: mock(() => {}), normalizeRequestSource: mock((provider: string, sourceHeader?: string | null) => provider === "api" && sourceHeader === "browser-extension" ? "browser_extension" : provider, diff --git a/src/routes/api.ts b/src/routes/api.ts index 7df4291..9610f8c 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -8,6 +8,7 @@ import { Hono } from "hono"; import { z } from "zod"; import { getConfig, type SecretsDetectionConfig } from "../config"; +import { logRequest, normalizeRequestSource } from "../logging/logger"; import { createPlaceholderContext, type PlaceholderContext } from "../masking/context"; import { filterAllowlistedEntities, @@ -18,7 +19,6 @@ import { import { mask as maskPII } from "../pii/mask"; import { detectSecrets } from "../secrets/detect"; import { maskSecrets } from "../secrets/mask"; -import { logRequest, normalizeRequestSource } from "../services/logger"; import { createLogData } from "./utils"; export const apiRoutes = new Hono(); diff --git a/src/routes/codex.test.ts b/src/routes/codex.test.ts index 39c3833..1f5d428 100644 --- a/src/routes/codex.test.ts +++ b/src/routes/codex.test.ts @@ -23,7 +23,7 @@ mock.module("../pii/detect", () => ({ }), })); -mock.module("../services/logger", () => ({ +mock.module("../logging/logger", () => ({ logRequest: mockLogRequest, })); diff --git a/src/routes/codex.ts b/src/routes/codex.ts index 336928e..b7bb4dc 100644 --- a/src/routes/codex.ts +++ b/src/routes/codex.ts @@ -4,6 +4,8 @@ import { Hono } from "hono"; import { proxy } from "hono/proxy"; import { z } from "zod"; import { getConfig } from "../config"; +import { formatMaskedRequestForLog } from "../logging/log-content"; +import { logRequest } from "../logging/logger"; import type { PlaceholderContext } from "../masking/context"; import { type CodexResponsesRequest, @@ -11,17 +13,15 @@ import { codexExtractor, } from "../masking/extractors/codex"; import { restoreResponse } from "../masking/restorer"; -import { createCodexUnmaskingStream } from "../providers/codex/stream-transformer"; -import { ProviderError } from "../providers/errors"; -import { formatMaskedRequestForLog } from "../services/log-content"; -import { logRequest } from "../services/logger"; -import type { PIIDetectResult } from "../services/pii"; +import type { PIIDetectResult } from "../pii/request"; import { PrivacyPipelineDetectionError, type PrivacyPipelineResult, processPrivacyPipeline, -} from "../services/privacy-pipeline"; -import type { SecretsProcessResult } from "../services/secrets"; +} from "../privacy/pipeline"; +import { createCodexUnmaskingStream } from "../providers/codex/stream-transformer"; +import { ProviderError } from "../providers/errors"; +import type { SecretsProcessResult } from "../secrets/request"; import { createLogData, errorFormats, diff --git a/src/routes/dashboard.tsx b/src/routes/dashboard.tsx index d36daaa..3b197bd 100644 --- a/src/routes/dashboard.tsx +++ b/src/routes/dashboard.tsx @@ -4,7 +4,7 @@ import { basicAuth } from "hono/basic-auth"; import { tailwind } from "hono-tailwind"; import { z } from "zod"; import { getConfig } from "../config"; -import { getLogger } from "../services/logger"; +import { getLogger } from "../logging/logger"; import DashboardPage from "../views/dashboard/page"; const LogsQuerySchema = z.object({ diff --git a/src/routes/health.ts b/src/routes/health.ts index b888e6e..5b4f39c 100644 --- a/src/routes/health.ts +++ b/src/routes/health.ts @@ -1,7 +1,7 @@ import { Hono } from "hono"; import { getConfig } from "../config"; +import { healthCheck as checkDetector } from "../pii/request"; import { checkLocalHealth } from "../providers/local"; -import { healthCheck as checkDetector } from "../services/pii"; export const healthRoutes = new Hono(); diff --git a/src/routes/openai.ts b/src/routes/openai.ts index 48269ad..becfb03 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -3,9 +3,17 @@ import type { Context } from "hono"; import { Hono } from "hono"; import { proxy } from "hono/proxy"; import { getConfig, type MaskingConfig } from "../config"; +import { formatMaskedRequestForLog } from "../logging/log-content"; +import { logRequest } from "../logging/logger"; import type { PlaceholderContext } from "../masking/context"; import { openaiExtractor } from "../masking/extractors/openai"; import { restoreResponse } from "../masking/restorer"; +import type { PIIDetectResult } from "../pii/request"; +import { + PrivacyPipelineDetectionError, + type PrivacyPipelineResult, + processPrivacyPipeline, +} from "../privacy/pipeline"; import { callLocal } from "../providers/local"; import { callOpenAI, getOpenAIInfo, type ProviderResult } from "../providers/openai/client"; import { createUnmaskingStream } from "../providers/openai/stream-transformer"; @@ -14,15 +22,7 @@ import { OpenAIRequestSchema, type OpenAIResponse, } from "../providers/openai/types"; -import { formatMaskedRequestForLog } from "../services/log-content"; -import { logRequest } from "../services/logger"; -import type { PIIDetectResult } from "../services/pii"; -import { - PrivacyPipelineDetectionError, - type PrivacyPipelineResult, - processPrivacyPipeline, -} from "../services/privacy-pipeline"; -import type { SecretsProcessResult } from "../services/secrets"; +import type { SecretsProcessResult } from "../secrets/request"; import { createLogData, errorFormats, diff --git a/src/routes/utils.ts b/src/routes/utils.ts index 2b1616e..4e08f34 100644 --- a/src/routes/utils.ts +++ b/src/routes/utils.ts @@ -1,10 +1,10 @@ import type { Context } from "hono"; import { getConfig } from "../config"; +import type { RequestLogData, RequestSource } from "../logging/logger"; +import { logRequest } from "../logging/logger"; +import type { PIIDetectResult } from "../pii/request"; import { ProviderError } from "../providers/errors"; -import type { RequestLogData, RequestSource } from "../services/logger"; -import { logRequest } from "../services/logger"; -import type { PIIDetectResult } from "../services/pii"; -import type { SecretsProcessResult } from "../services/secrets"; +import type { SecretsProcessResult } from "../secrets/request"; // ============================================================================ // Error Response Types & Formatting diff --git a/src/services/secrets.ts b/src/secrets/request.ts similarity index 94% rename from src/services/secrets.ts rename to src/secrets/request.ts index 6b0fa2d..23646c9 100644 --- a/src/services/secrets.ts +++ b/src/secrets/request.ts @@ -1,12 +1,12 @@ /** - * Secrets Service - detect and mask secrets in requests + * Secrets request helpers - detect and mask secrets in requests */ import type { SecretsDetectionConfig } from "../config"; import type { PlaceholderContext } from "../masking/context"; import type { RequestExtractor } from "../masking/types"; -import { detectSecretsInRequest, type MessageSecretsResult } from "../secrets/detect"; -import { maskRequest } from "../secrets/mask"; +import { detectSecretsInRequest, type MessageSecretsResult } from "./detect"; +import { maskRequest } from "./mask"; export interface SecretsProcessResult { blocked: boolean;