diff --git a/src/lib/privacy-layer.ts b/src/lib/privacy-layer.ts index 6431e37..858ae64 100644 --- a/src/lib/privacy-layer.ts +++ b/src/lib/privacy-layer.ts @@ -1,3 +1,29 @@ +/** + * privacy-layer.ts — sensitivity analysis & privacy method selection (Presidio-aware) + * + * Composes Microsoft Presidio's PII-detection architecture (in + * `./presidio-recognizers`) with the project's existing keyword-based + * sensitivity scoring. The exposed API surface is fully backward + * compatible: legacy consumers (privacy-layer.test.ts, + * privacy-innovations.ts) see no contract changes. + * + * - `analyzeSensitivity` runs the legacy keyword scan AND a Presidio + * PII pass; the Presidio signal is *additive* — it boosts the + * sensitivity score, appends entity-type keywords, and records a + * "PII detected" reason without displacing the keyword-based + * category decision. + * - `getPrivacyResult`, `processWithPrivacy` retain their original + * semantics for the synthetic-result demo. + * - `SENSITIVITY_THRESHOLDS` is re-exported here for back-compat; the + * canonical source remains `./constants`. + */ + +import { + analyzePII, + PRESIDIO_RECOGNIZERS, + type RecognizerResult, +} from "./presidio-recognizers"; + export type PrivacyLevel = "MAXIMUM" | "HIGH" | "MEDIUM" | "STANDARD" | "LOW"; // NOTE: SENSITIVITY_THRESHOLDS is also exported from this file for backward compatibility. @@ -39,143 +65,222 @@ export interface SensitivityAnalysis { sensitivityScore: number; // 0-100 recommendedLevel: PrivacyLevel; reasons: string[]; + /** + * Recognizer-level PII findings (Presidio-style). Populated when the + * Presidio analyzer finds structured PII (CC, SSN, email, etc.) in the + * input. Empty array when no findings. + */ + piiFindings: RecognizerResult[]; + /** + * Unique Presidio entity types detected. Used by the UI to show an + * entity-type badge ("US_SSN", "EMAIL_ADDRESS", etc.). + */ + piiEntityTypes: string[]; } +// ---------------------------------------------------------------------------- +// Sensitivity keyword table (Presidio-aware: aligned with the entity types +// emitted by PRESIDIO_RECOGNIZERS so the category output remains stable) +// ---------------------------------------------------------------------------- + const SENSITIVITY_KEYWORDS: Record = { medical: { - keywords: ["medical", "health", "patient", "diagnosis", "symptom", "prescription", "doctor", "hospital", "treatment", "condition", "blood", "lab", "test result", "vaccine", "surgery", "therapy", "mental health", "psychiatric", "disability", "medication", "pharmacy"], - weight: 40 + keywords: ["medical", "health", "patient", "diagnosis", "symptom", "prescription", "doctor", "hospital", "treatment", "condition", "blood", "lab", "test result", "vaccine", "surgery", "therapy", "mental health", "psychiatric", "disability", "medication", "pharmacy", "npi", "emr", "hipaa"], + weight: 40, }, financial: { keywords: ["bank", "credit card", "account", "transaction", "salary", "income", "tax", "investment", "stock", "password", "pin", "ssn", "social security", "routing", "balance", "loan", "mortgage", "crypto", "wallet", "iban", "swift"], - weight: 38 + weight: 38, }, legal: { keywords: ["legal", "attorney", "lawyer", "contract", "nda", "confidential", "privileged", "court", "lawsuit", "litigation", "deposition", "settlement", "trade secret", "intellectual property", "patent", "copyright", "compliance", "regulatory", "subpoena"], - weight: 36 + weight: 36, }, personal_identity: { keywords: ["ssn", "passport", "driver license", "id", "birthdate", "address", "phone number", "email", "social security", "national id", "biometric", "fingerprint", "face scan", "dna", "family", "children", "spouse"], - weight: 35 + weight: 35, }, government: { keywords: ["classified", "top secret", "government", "military", "defense", "intelligence", "cia", "fbi", "nsa", "clearance", "national security", "diplomatic", "embassy", "consulate", "restricted", "secret"], - weight: 42 + weight: 42, }, business_strategy: { keywords: ["strategy", "merger", "acquisition", "ipo", "board meeting", "executive", "cfo", "ceo", "revenue", "forecast", "pipeline", "competitive analysis", "market share", "r&d", "proprietary", "internal only", "board", "investor", "quarterly", "roadmap"], - weight: 32 + weight: 32, }, credentials: { keywords: ["password", "api key", "token", "secret", "credential", "login", "authentication", "private key", "certificate", "ssh", "vpn", "access code", "otp", "2fa", "mfa"], - weight: 34 + weight: 34, }, personal_life: { keywords: ["diary", "journal", "therapy", "counseling", "personal photo", "private message", "chat", "intimate", "relationship", "dating", "family issue", "trauma", "addiction", "rehab", "mental state", "emotion"], - weight: 28 + weight: 28, }, general_sensitive: { keywords: ["confidential", "private", "personal", "sensitive", "do not share", "internal", "restricted", "proprietary"], - weight: 18 + weight: 18, }, analytics: { keywords: ["analytics", "metrics", "statistics", "survey", "aggregate", "trend", "usage data", "performance", "kpi", "dashboard", "report", "summary"], - weight: 8 + weight: 8, }, public: { keywords: ["public", "news", "article", "blog", "social media", "tweet", "press release", "marketing", "advertisement", "announcement", "open source", "general knowledge", "wikipedia", "weather", "sports", "entertainment"], - weight: -15 - } + weight: -15, + }, +}; + +/** + * PII-based sensitivity boosts derived from Presidio entity types. + * Mirrors Presidio's notion of "context-aware enhancement" — when the + * recognizer reports a result, the corresponding score gets a weight + * bump proportional to recognizer confidence. + */ +const PII_ENTITY_WEIGHTS: Record = { + US_SSN: 22, + CREDIT_CARD: 24, + IBAN: 20, + US_BANK_NUMBER: 20, + MEDICAL_LICENSE: 22, + US_PASSPORT: 22, + US_DRIVER_LICENSE: 18, + CRYPTO_WALLET: 16, + API_KEY: 24, + EMAIL_ADDRESS: 12, + PHONE_NUMBER: 14, + IP_ADDRESS: 8, + URL: 4, +}; + +/** + * Human-readable label per PII entity. Used when surfacing findings in + * the `reasons` array. + */ +const PII_ENTITY_LABELS: Record = { + US_SSN: "Social Security Number detected", + CREDIT_CARD: "Credit card number detected", + IBAN: "International bank account number detected", + US_BANK_NUMBER: "Bank routing number detected", + MEDICAL_LICENSE: "National Provider Identifier (NPI) detected", + US_PASSPORT: "US passport number detected", + US_DRIVER_LICENSE: "Driver's license number detected", + CRYPTO_WALLET: "Cryptocurrency wallet address detected", + API_KEY: "API key / secret token detected", + EMAIL_ADDRESS: "Email address detected", + PHONE_NUMBER: "Phone number detected", + IP_ADDRESS: "IP address detected", + URL: "URL detected", +}; + +const CATEGORY_REASON_LABELS: Record = { + medical: "Medical/health information detected", + financial: "Financial/banking data detected", + legal: "Legal/attorney-privileged content detected", + personal_identity: "Personal identity information (PII) detected", + government: "Government/classified information detected", + business_strategy: "Business strategy/internal documents detected", + credentials: "Credentials/secrets detected", + personal_life: "Personal/private life content detected", + general_sensitive: "General sensitive keywords detected", + analytics: "Analytics/aggregate data detected", + public: "Public/general information detected", }; /** - * Analyzes the sensitivity of input text and recommends a privacy level. - * - * Uses keyword matching across 11 categories (medical, financial, legal, etc.) - * with weighted scoring to determine sensitivity score (0-100). - * + * Analyze the sensitivity of input text. Combines the legacy keyword + * matrix with a Presidio PII pass. The Presidio signal is *additive*: + * + * - Score boost (capped at 100, additive on top of keyword score). + * - Detected entity types appended to `keywords` (low-snake form: + * "us_ssn", "email_address", etc.). + * - One `reasons` entry per unique PII entity type. + * - `piiFindings`/`piiEntityTypes` exposed for downstream tools. + * * @param request - The user's request/query text * @param data - Optional additional data to analyze - * @returns Sensitivity analysis with score, keywords, and recommended level - * - * @example - * ```typescript - * const analysis = analyzeSensitivity( - * "Analyze this patient record", - * "Patient ID: 12345, Diagnosis: Diabetes" - * ); - * console.log(analysis.sensitivityScore); // 85 - * console.log(analysis.recommendedLevel); // "MAXIMUM" - * ``` + * @returns Sensitivity analysis with score, keywords, recommended level, + * PII findings, and human-readable reasons. */ function analyzeSensitivity(request: string, data?: string): SensitivityAnalysis { - const text = `${request} ${data || ""}`.toLowerCase(); + const text = `${request} ${data ?? ""}`.toLowerCase(); let totalScore = 0; const matchedCategories: string[] = []; const matchedKeywords: string[] = []; const reasons: string[] = []; + // ---- 1. Legacy keyword matrix ---- for (const [category, config] of Object.entries(SENSITIVITY_KEYWORDS)) { let categoryMatches = 0; const categoryKeywords: string[] = []; - + for (const keyword of config.keywords) { if (text.includes(keyword.toLowerCase())) { - categoryMatches++; + categoryMatches += 1; categoryKeywords.push(keyword); } } - + if (categoryMatches > 0) { - totalScore += config.weight + (categoryMatches * 3); + totalScore += config.weight + categoryMatches * 3; matchedCategories.push(category); matchedKeywords.push(...categoryKeywords); - - const categoryNames: Record = { - medical: "Medical/health information detected", - financial: "Financial/banking data detected", - legal: "Legal/attorney-privileged content detected", - personal_identity: "Personal identity information (PII) detected", - government: "Government/classified information detected", - business_strategy: "Business strategy/internal documents detected", - credentials: "Credentials/secrets detected", - personal_life: "Personal/private life content detected", - general_sensitive: "General sensitive keywords detected", - analytics: "Analytics/aggregate data detected", - public: "Public/general information detected" - }; - reasons.push(categoryNames[category] || `${category} detected`); + const label = CATEGORY_REASON_LABELS[category] ?? `${category} detected`; + if (!reasons.includes(label)) reasons.push(label); } } - // Length heuristic - longer documents with company data might be sensitive - if ((data?.length || 0) > 2000) { + // Length heuristic — longer documents warrant extra scrutiny. + const dataLength = data?.length ?? 0; + if (dataLength > 2000) { totalScore += 5; - reasons.push("Large document detected - increased scrutiny applied"); + if (!reasons.includes("Large document detected - increased scrutiny applied")) { + reasons.push("Large document detected - increased scrutiny applied"); + } + } + + // ---- 2. Presidio PII scan (additive) ---- + const piiFindings: RecognizerResult[] = data !== undefined || request.length > 0 + ? analyzePII(`${request}${data !== undefined ? " " + data : ""}`) + : []; + const piiEntityTypes = Array.from(new Set(piiFindings.map((f) => f.entityType))); + + if (piiFindings.length > 0) { + let piiBoostTotal = 0; + let boostCount = 0; + for (const finding of piiFindings) { + const weight = PII_ENTITY_WEIGHTS[finding.entityType] ?? 6; + const boost = weight * Math.max(0.5, Math.min(1, finding.score)); + piiBoostTotal += boost; + boostCount += 1; + // Surface the entity itself as a "keyword" so existing UI badges + // (which iterate over `keywords`) can pick it up. + matchedKeywords.push(finding.entityType.toLowerCase()); + } + // Cap the additive boost per-call (avoid runaway from 100 tiny matches). + totalScore += Math.min(40, piiBoostTotal + Math.min(20, boostCount)); + + for (const entityType of piiEntityTypes) { + const label = PII_ENTITY_LABELS[entityType] ?? `${entityType} detected`; + if (!reasons.includes(label)) reasons.push(label); + } } - // Cap score totalScore = Math.max(0, Math.min(100, totalScore)); - // Determine recommended level using constants + // ---- 3. Pick the recommended level + primary category ---- let recommendedLevel: PrivacyLevel; - if (totalScore >= SENSITIVITY_THRESHOLDS.MAXIMUM) { - recommendedLevel = "MAXIMUM"; - } else if (totalScore >= SENSITIVITY_THRESHOLDS.HIGH) { - recommendedLevel = "HIGH"; - } else if (totalScore >= SENSITIVITY_THRESHOLDS.MEDIUM) { - recommendedLevel = "MEDIUM"; - } else if (totalScore >= SENSITIVITY_THRESHOLDS.STANDARD) { - recommendedLevel = "STANDARD"; - } else { - recommendedLevel = "LOW"; - } + if (totalScore >= SENSITIVITY_THRESHOLDS.MAXIMUM) recommendedLevel = "MAXIMUM"; + else if (totalScore >= SENSITIVITY_THRESHOLDS.HIGH) recommendedLevel = "HIGH"; + else if (totalScore >= SENSITIVITY_THRESHOLDS.MEDIUM) recommendedLevel = "MEDIUM"; + else if (totalScore >= SENSITIVITY_THRESHOLDS.STANDARD) recommendedLevel = "STANDARD"; + else recommendedLevel = "LOW"; - // Determine primary category - let primaryCategory = matchedCategories[0] || "general"; + // Prefer medical/government as primary when present (per legacy rule). + let primaryCategory = matchedCategories[0] ?? "general"; if (matchedCategories.includes("medical") || matchedCategories.includes("government")) { - primaryCategory = matchedCategories.find(c => c === "medical" || c === "government") || primaryCategory; + const preferred = matchedCategories.find((c) => c === "medical" || c === "government"); + if (preferred) primaryCategory = preferred; } return { @@ -183,28 +288,18 @@ function analyzeSensitivity(request: string, data?: string): SensitivityAnalysis keywords: Array.from(new Set(matchedKeywords)), sensitivityScore: totalScore, recommendedLevel, - reasons + reasons, + piiFindings, + piiEntityTypes, }; } /** - * Gets the privacy method details for a given privacy level. - * - * Returns comprehensive information about the privacy method including: - * - Processing method and description - * - Speed and quality characteristics - * - Security guarantees - * - Step-by-step processing pipeline - * - * @param level - The privacy level (MAXIMUM, HIGH, MEDIUM, STANDARD, LOW) - * @returns Complete privacy method details - * - * @example - * ```typescript - * const result = getPrivacyResult("MAXIMUM"); - * console.log(result.method); // "Local Model" - * console.log(result.dataNeverLeavesDevice); // true - * ``` + * Return the privacy method details for a given privacy level. + * + * Comprehensive {@link PrivacyResult}: processing method, speed/quality, + * security guarantees, and step-by-step pipeline. Pure data — no side + * effects and safe to call from anywhere. */ function getPrivacyResult(level: PrivacyLevel): PrivacyResult { const results: Record = { @@ -220,14 +315,15 @@ function getPrivacyResult(level: PrivacyLevel): PrivacyResult { cloudSeesRawData: false, hardwareEnforced: false, mathematicallyProvable: false, - explanation: "Your data is processed entirely on your device using a local AI model. Nothing is sent to the cloud.", + explanation: + "Your data is processed entirely on your device using a local AI model. Nothing is sent to the cloud.", steps: [ { title: "Load llama.cpp Runtime", description: "Initialize llama.cpp (GGUF runtime, ~2MB)", location: "device", status: "completed" }, { title: "Load Phi-3 Mini Q4", description: "Load quantized model (GGUF, ~1.3GB) into device memory", location: "device", status: "completed" }, { title: "Tokenize Input", description: "Convert text to tokens via llama.cpp tokenizer", location: "device", status: "completed" }, { title: "Inference (CPU)", description: "Run forward pass through 32 transformer layers on-device", location: "device", status: "completed" }, - { title: "Decode Output", description: "Convert generated tokens back to readable text", location: "device", status: "completed" } - ] + { title: "Decode Output", description: "Convert generated tokens back to readable text", location: "device", status: "completed" }, + ], }, HIGH: { level: "HIGH", @@ -241,13 +337,14 @@ function getPrivacyResult(level: PrivacyLevel): PrivacyResult { cloudSeesRawData: false, hardwareEnforced: false, mathematicallyProvable: false, - explanation: "The AI model is split: your device processes the first layers (raw data stays local), intermediate representations go to the cloud for heavy computation, then final layers run back on your device.", + explanation: + "The AI model is split: your device processes the first layers (raw data stays local), intermediate representations go to the cloud for heavy computation, then final layers run back on your device.", steps: [ { title: "Feature Extraction (Device)", description: "Process first layers on device - raw data stays local", location: "device", status: "completed" }, { title: "Intermediate Transfer", description: "Send transformed representation (not raw data)", location: "cloud", status: "completed" }, { title: "Heavy Computation (Cloud)", description: "Process middle layers with cloud power", location: "cloud", status: "completed" }, - { title: "Final Layers (Device)", description: "Complete processing on device - result stays local", location: "device", status: "completed" } - ] + { title: "Final Layers (Device)", description: "Complete processing on device - result stays local", location: "device", status: "completed" }, + ], }, MEDIUM: { level: "MEDIUM", @@ -261,15 +358,16 @@ function getPrivacyResult(level: PrivacyLevel): PrivacyResult { cloudSeesRawData: false, hardwareEnforced: true, mathematicallyProvable: false, - explanation: "Data is encrypted and sent to a Trusted Execution Environment (TEE) in the cloud. The cloud provider cannot access your data, even with root access. Hardware-enforced isolation.", + explanation: + "Data is encrypted and sent to a Trusted Execution Environment (TEE) in the cloud. The cloud provider cannot access your data, even with root access. Hardware-enforced isolation.", steps: [ { title: "Encrypt Data", description: "Encrypt with TEE public key on device", location: "device", status: "completed" }, { title: "Send to Cloud", description: "Encrypted data transmitted securely", location: "cloud", status: "completed" }, { title: "TEE Decryption", description: "Decrypt inside hardware-isolated enclave", location: "secure-enclave", status: "completed" }, { title: "Process in Enclave", description: "AI inference inside secure hardware", location: "secure-enclave", status: "completed" }, { title: "Encrypt Result", description: "Encrypt result before leaving enclave", location: "secure-enclave", status: "completed" }, - { title: "Return & Decrypt", description: "Receive and decrypt result on device", location: "device", status: "completed" } - ] + { title: "Return & Decrypt", description: "Receive and decrypt result on device", location: "device", status: "completed" }, + ], }, STANDARD: { level: "STANDARD", @@ -283,13 +381,14 @@ function getPrivacyResult(level: PrivacyLevel): PrivacyResult { cloudSeesRawData: true, hardwareEnforced: false, mathematicallyProvable: true, - explanation: "Calibrated noise is added to your data before sending to the cloud. The noise protects your individual privacy while still allowing accurate aggregate analysis. Mathematically provable privacy guarantees.", + explanation: + "Calibrated noise is added to your data before sending to the cloud. The noise protects your individual privacy while still allowing accurate aggregate analysis. Mathematically provable privacy guarantees.", steps: [ { title: "Add Noise", description: "Add calibrated statistical noise to data", location: "device", status: "completed" }, { title: "Send Noisy Data", description: "Transmit perturbed data to cloud", location: "cloud", status: "completed" }, { title: "Process", description: "AI processes noisy data (patterns preserved)", location: "cloud", status: "completed" }, - { title: "Return Result", description: "Result based on differentially private data", location: "cloud", status: "completed" } - ] + { title: "Return Result", description: "Result based on differentially private data", location: "cloud", status: "completed" }, + ], }, LOW: { level: "LOW", @@ -303,13 +402,14 @@ function getPrivacyResult(level: PrivacyLevel): PrivacyResult { cloudSeesRawData: true, hardwareEnforced: false, mathematicallyProvable: false, - explanation: "Standard encrypted connection to cloud AI. Best performance and quality. Suitable for public or non-sensitive information.", + explanation: + "Standard encrypted connection to cloud AI. Best performance and quality. Suitable for public or non-sensitive information.", steps: [ { title: "TLS Encrypt", description: "Encrypt data with TLS for transit", location: "device", status: "completed" }, { title: "Cloud Processing", description: "Process with full cloud AI model", location: "cloud", status: "completed" }, - { title: "Return Result", description: "Encrypted result returned via TLS", location: "cloud", status: "completed" } - ] - } + { title: "Return Result", description: "Encrypted result returned via TLS", location: "cloud", status: "completed" }, + ], + }, }; return results[level]; @@ -328,79 +428,48 @@ export interface ProcessResponse { } /** - * Main function for privacy-aware processing. - * - * Analyzes input sensitivity, selects appropriate privacy method, - * and returns simulated processing results. - * - * **Input Validation:** - * - Request must be non-empty string (max 10,000 chars) - * - Data must be string (max 100,000 chars) if provided - * - * **Processing Steps:** - * 1. Validate inputs - * 2. Analyze sensitivity - * 3. Determine privacy level (or use override) - * 4. Get privacy method details - * 5. Simulate AI processing - * - * @param req - Processing request with text and optional override - * @returns Processing response with analysis, privacy method, and result - * @throws Error if validation fails or processing errors occur - * - * @example - * ```typescript - * const result = await processWithPrivacy({ - * request: "Analyze this patient medical record", - * data: "Patient ID: 12345\nDiagnosis: Type 2 Diabetes...", - * overrideLevel: "MAXIMUM" // Optional: force specific level - * }); - * - * console.log(result.privacy.level); // "MAXIMUM" - * console.log(result.analysis.sensitivityScore); // 85 - * console.log(result.simulatedResult); // AI response - * ``` + * Top-level entry point for privacy-aware AI processing. Validates input, + * runs the Presidio-aware sensitivity analysis, picks the privacy level, + * and returns the matching {@link PrivacyResult}. + * + * @param req - Request with text and optional override level + * @returns Combined analysis + privacy-method description + simulated result + * @throws Error when validation fails or processing errors */ export async function processWithPrivacy(req: ProcessRequest): Promise { try { - // Input validation — check type first, then emptiness + // Input validation — check type first, then emptiness. if (req.request === null || req.request === undefined || typeof req.request !== "string") { throw new Error("Request must be a non-empty string"); } - if (req.request.trim().length === 0) { throw new Error("Request cannot be empty"); } - if (req.request.length > 10000) { throw new Error("Request exceeds maximum length of 10,000 characters"); } - if (req.data && req.data.length > 100000) { throw new Error("Data exceeds maximum length of 100,000 characters"); } - - // Step 1: Analyze sensitivity + + // 1. Sensitivity analysis (now Presidio-aware). const analysis = analyzeSensitivity(req.request, req.data); - - // Step 2: Determine privacy level (use override if provided) - const level = req.overrideLevel || analysis.recommendedLevel; - - // Step 3: Get privacy method details + + // 2. Privacy level — override wins. + const level = req.overrideLevel ?? analysis.recommendedLevel; + + // 3. Privacy method details. const privacy = getPrivacyResult(level); - - // Step 4: Simulate AI processing result + + // 4. Simulated AI result. const simulatedResult = generateSimulatedResult(req.request, level, analysis.category); - - // Simulate async processing - await new Promise(resolve => setTimeout(resolve, 600)); - - return { - analysis, - privacy, - simulatedResult - }; + + // Simulate async processing. + await new Promise((resolve) => setTimeout(resolve, 600)); + + return { analysis, privacy, simulatedResult }; } catch (error) { + // eslint-disable-next-line no-console console.error("processWithPrivacy error:", error); throw new Error(`Privacy processing failed: ${error instanceof Error ? error.message : "Unknown error"}`); } @@ -412,24 +481,45 @@ function generateSimulatedResult(request: string, level: PrivacyLevel, category: HIGH: "Split Learning", MEDIUM: "TEE Secure", STANDARD: "Differential Privacy", - LOW: "Cloud" + LOW: "Cloud", }; - + const categoryResults: Record = { - medical: `Privacy-preserving medical analysis completed using ${levelLabels[level]} mode.\n\nDetected medical content. Analysis performed without exposing patient-identifiable information. Key observations focus on general patterns rather than individual records.`, - financial: `Secure financial analysis via ${levelLabels[level]}.\n\nSensitive financial data was protected throughout processing. Analysis maintains data utility while preserving confidentiality of specific accounts and transactions.`, - legal: `Legal document analysis completed with ${levelLabels[level]} privacy.\n\nAttorney-client privileged content processed securely. Analysis extracts general insights without exposing sensitive legal strategy or confidential communications.`, - credentials: `Credential security scan via ${levelLabels[level]}.\n\nSecrets and credentials were handled with maximum protection. No sensitive tokens were exposed to cloud infrastructure during analysis.`, - government: `Classified data processing via ${levelLabels[level]}.\n\nGovernment-sensitive information handled with appropriate security controls. Analysis completed within enforced privacy boundaries.`, - business_strategy: `Business strategy analysis via ${levelLabels[level]}.\n\nCompetitive and strategic information processed securely. Insights extracted without exposing proprietary details or internal planning data.`, - personal_identity: `PII analysis via ${levelLabels[level]}.\n\nPersonal identity information was protected throughout processing. Analysis maintains individual privacy while delivering useful aggregate results.`, - personal_life: `Personal content analysis via ${levelLabels[level]}.\n\nPrivate life content processed with appropriate privacy safeguards. Personal details were not exposed to external systems.`, - analytics: `Analytics processing via ${levelLabels[level]}.\n\nStatistical analysis completed with privacy-preserving techniques. Aggregate patterns identified while individual contributions remain protected.`, - public: `General analysis via ${levelLabels[level]}.\n\nPublic/non-sensitive information processed with optimized cloud performance. Fastest response time achieved with standard security measures.`, - general: `Analysis completed via ${levelLabels[level]}.\n\nContent analyzed with automatically-selected privacy protection. AI determined the optimal privacy level based on content sensitivity analysis.` + medical: + `Privacy-preserving medical analysis completed using ${levelLabels[level]} mode.\n\nDetected medical content. Analysis performed without exposing patient-identifiable information. Key observations focus on general patterns rather than individual records.`, + financial: + `Secure financial analysis via ${levelLabels[level]}.\n\nSensitive financial data was protected throughout processing. Analysis maintains data utility while preserving confidentiality of specific accounts and transactions.`, + legal: + `Legal document analysis completed with ${levelLabels[level]} privacy.\n\nAttorney-client privileged content processed securely. Analysis extracts general insights without exposing sensitive legal strategy or confidential communications.`, + credentials: + `Credential security scan via ${levelLabels[level]}.\n\nSecrets and credentials were handled with maximum protection. No sensitive tokens were exposed to cloud infrastructure during analysis.`, + government: + `Classified data processing via ${levelLabels[level]}.\n\nGovernment-sensitive information handled with appropriate security controls. Analysis completed within enforced privacy boundaries.`, + business_strategy: + `Business strategy analysis via ${levelLabels[level]}.\n\nCompetitive and strategic information processed securely. Insights extracted without exposing proprietary details or internal planning data.`, + personal_identity: + `PII analysis via ${levelLabels[level]}.\n\nPersonal identity information was protected throughout processing. Analysis maintains individual privacy while delivering useful aggregate results.`, + personal_life: + `Personal content analysis via ${levelLabels[level]}.\n\nPrivate life content processed with appropriate privacy safeguards. Personal details were not exposed to external systems.`, + analytics: + `Analytics processing via ${levelLabels[level]}.\n\nStatistical analysis completed with privacy-preserving techniques. Aggregate patterns identified while individual contributions remain protected.`, + public: + `General analysis via ${levelLabels[level]}.\n\nPublic/non-sensitive information processed with optimized cloud performance. Fastest response time achieved with standard security measures.`, + general: + `Analysis completed via ${levelLabels[level]}.\n\nContent analyzed with automatically-selected privacy protection. AI determined the optimal privacy level based on content sensitivity analysis.`, }; - return categoryResults[category] || categoryResults["general"]; + return categoryResults[category] ?? categoryResults["general"]!; } export { analyzeSensitivity, getPrivacyResult }; + +/** + * Re-exports of the Presidio framework for callers wiring + * privacy-layer upstream consumers (e.g. privacy-innovations.ts). + * + * `PRESIDIO_RECOGNIZERS` is also exposed under its trained instance so + * existing tests & downstream modules can synchronously reference the + * recognizer list without race conditions during module init. + */ +export { PRESIDIO_RECOGNIZERS };