Back to .md Directory

Database Sanitization Framework - User Stories

This document contains 28 user stories across 6 phases for building a domain-agnostic SQL Server database sanitization framework in Python.

May 2, 2026
0 downloads
0 views
ai rag
View source

Database Sanitization Framework - User Stories

Overview

This document contains 28 user stories across 6 phases for building a domain-agnostic SQL Server database sanitization framework in Python.

Status Legend: ⬜ Not Started | 🟦 In Progress | āœ… Completed


PHASE 1: Foundation & Infrastructure (5 Stories)

Story 1.1: Database Connection Manager

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 1-2 days

User Story:
As a developer, I want a robust SQL Server connection manager so that I can reliably connect to databases with retry logic and connection pooling.

Acceptance Criteria:

  • āœ… Supports both SQL Server Authentication and Windows Authentication
  • āœ… Implements exponential backoff retry (3 attempts: 1s, 2s, 4s delays)
  • āœ… Connection pooling to minimize overhead
  • āœ… Graceful timeout handling (30s default, configurable)
  • āœ… Health check before executing queries
  • āœ… Context manager for automatic cleanup
  • āœ… No credentials logged

Technical Details:

  • File: src/database/connection_manager.py
  • Dependencies: pyodbc
  • Key Methods: connect(), execute_query(), execute_batch(), health_check()

Edge Cases:

  • Network partitions during long-running operations
  • SQL Server in single-user mode
  • TLS/SSL certificate validation failures
  • Connection pool exhaustion

Story 1.2: Configuration Management System

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 1 day

User Story:
As a developer, I want a typed configuration system so that I can manage settings from files, environment variables, and user input.

Acceptance Criteria:

  • āœ… Load from JSON files (schema config, PII config)
  • āœ… Override with environment variables (DB credentials)
  • āœ… Validate configuration with Pydantic models
  • āœ… Clear error messages for missing/invalid config
  • āœ… Support multiple environments (dev, staging, prod)

Technical Details:

  • Files: src/config/config_models.py, src/config/config_loader.py
  • Dependencies: pydantic, python-dotenv
  • Config Models: DatabaseConfig, PIIColumnConfig, PIIConfig, SanitizationConfig

Implementation Summary:

  • āœ… Pydantic-based models with comprehensive validation
  • āœ… ConfigLoader with JSON parsing and env var overrides
  • āœ… Thread-safe singleton pattern with caching
  • āœ… 75 unit tests + 11 integration tests (97% coverage)
  • āœ… Example config files and documentation
  • āœ… Environment variable pattern: SANITIZATION_{SECTION}_{KEY}

Sample Config Structure:

{
  "database": {
    "server": "localhost",
    "database": "SanitizationTest",
    "auth_type": "windows",
    "timeout": 30,
    "batch_size": 10000
  },
  "pii_columns": [
    {
      "schema": "dbo",
      "table": "Customers",
      "column": "Email",
      "pii_type": "email",
      "nullable": false
    }
  ]
}

Story 1.3: Structured Logging Framework

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 1 day

User Story:
As a developer, I want a structured logging system so that I can debug issues without exposing PII.

Acceptance Criteria:

  • āœ… JSON-formatted logs with timestamps, levels, correlation IDs
  • āœ… Automatic PII redaction (no raw sensitive data)
  • āœ… Configurable log levels (DEBUG, INFO, WARNING, ERROR)
  • āœ… File and console output support
  • āœ… Correlation IDs for tracing multi-step operations
  • āœ… Log rotation (daily, max 10 files)

Technical Details:

  • Files:
    • src/logging/log_config.py - Pydantic configuration models
    • src/logging/pii_patterns.py - Compiled regex patterns for PII detection
    • src/logging/formatters.py - JSON and colored console formatters
    • src/logging/filters.py - PII redaction and correlation filters
    • src/logging/correlation.py - Context manager for correlation IDs
    • src/logging/logger.py - Singleton logger manager
    • src/logging/adapter.py - Convenience logging adapter with helper methods
    • src/logging/__init__.py - Module initialization
  • Key Features:
    • Thread-safe correlation ID tracking using contextvars
    • Automatic PII redaction for: email, phone, SSN, credit cards, API keys, IP addresses
    • Rotating file handler with size and time-based rotation
    • Colored console output for development
    • Integration with SanitizationConfig

Implementation Summary:

  • āœ… Complete structured logging framework with 62 unit tests (100% pass rate)
  • āœ… JSON formatter for machine-readable logs
  • āœ… PII redaction filter with configurable patterns
  • āœ… Correlation context manager using contextvars for thread safety
  • āœ… Singleton logger manager with configuration support
  • āœ… Context logger adapter with convenience methods (log_operation_start, log_operation_end, etc.)
  • āœ… TimedOperation context manager for automatic operation timing
  • āœ… Updated SanitizationConfig to include logging configuration
  • āœ… Updated config example with logging section

Test Coverage:

  • āœ… 14 tests for formatters (JSON and colored console)
  • āœ… 17 tests for filters (PII redaction, correlation, level range)
  • āœ… 21 tests for correlation context (including thread isolation)
  • āœ… 10 tests for logger manager (singleton, configuration, handlers)

PII Redaction Patterns:

  • Emails: \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b → ***@***
  • Phones: \d{3}[-.]?\d{3}[-.]?\d{4} → ***-***-****
  • SSN: \d{3}-\d{2}-\d{4} → ***-**-****
  • Credit Cards, API Keys, IP Addresses also supported

Story 1.4: Exception Hierarchy & Error Handling

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 0.5 days

User Story:
As a developer, I want a custom exception hierarchy so that I can handle different failure scenarios appropriately.

Acceptance Criteria:

  • āœ… Base SanitizationError exception
  • āœ… Specific exceptions for each module
  • āœ… Include context (table, column, operation) in exceptions
  • āœ… Support error chaining (preserve original exception)
  • āœ… Actionable error messages

Technical Details:

  • File: src/exceptions.py
  • Exception Classes:
    • SanitizationError (base)
    • DatabaseConnectionError
    • SchemaExtractionError
    • AIServiceError
    • DataValidationError
    • MaskingGenerationError
    • ReferentialIntegrityError
    • MappingTableError

Implementation Summary:

  • āœ… Complete exception hierarchy with 9 exception classes
  • āœ… Error codes in src/error_codes.py with domain grouping
  • āœ… Factory methods for common error scenarios
  • āœ… Context enrichment via add_context() method
  • āœ… Exception chaining via from_exception() factory
  • āœ… Exception serialization to dict for logging
  • āœ… 34 unit tests covering all exception types
  • āœ… Comprehensive docstrings and type hints

Story 1.5: Project Structure & Packaging

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 0.5 days

User Story:
As a developer, I want a well-organized project structure so that code is maintainable and testable.

Acceptance Criteria:

  • āœ… Standard Python package structure
  • āœ… requirements.txt with pinned versions
  • āœ… .env.example template
  • āœ… README with setup instructions
  • āœ… .gitignore for Python/SQL Server

Implementation Summary:

  • āœ… Complete project structure with src/, tests/, config/, examples/, scripts/
  • āœ… Comprehensive requirements.txt with pinned versions (pyodbc, pydantic, pytest, etc.)
  • āœ… Environment template at config/.env.example with documentation
  • āœ… Detailed README.md with setup instructions, usage examples, configuration guide
  • āœ… Complete .gitignore for Python, SQL Server, IDEs, testing artifacts
  • āœ… Package structure with init.py files and proper exports

Project Structure:

database-sanitization/
ā”œā”€ā”€ src/
│   ā”œā”€ā”€ __init__.py
│   ā”œā”€ā”€ database/
│   ā”œā”€ā”€ config/
│   ā”œā”€ā”€ masking/
│   ā”œā”€ā”€ sanitization/
│   ā”œā”€ā”€ mapping/
│   ā”œā”€ā”€ ai/
│   ā”œā”€ā”€ validation/
│   ā”œā”€ā”€ logging/
│   └── exceptions.py
ā”œā”€ā”€ tests/
ā”œā”€ā”€ config/
ā”œā”€ā”€ scripts/
ā”œā”€ā”€ requirements.txt
└── README.md

PHASE 2: Database Layer (5 Stories)

Story 2.1: Schema Metadata Extraction

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 2 days

User Story:
As a developer, I want to extract complete schema metadata so that I can understand table structures, relationships, and constraints.

Acceptance Criteria:

  • āœ… Extract all tables with schema names ([schema].[table])
  • āœ… Extract columns: data types, lengths, precision, scale, nullability
  • āœ… Identify primary keys (including composite keys)
  • āœ… Identify foreign keys with parent/child relationships
  • āœ… Identify unique constraints and indexes
  • āœ… Output as structured JSON
  • āœ… Handle special characters in names (proper [] escaping)

Technical Details:

  • File: src/database/schema_extractor.py
  • System Tables: sys.tables, sys.columns, sys.key_constraints, sys.foreign_keys
  • Key Method: extract_schema(database_name) -> Dict

Edge Cases:

  • Tables without primary keys
  • Composite primary/foreign keys
  • Self-referencing foreign keys
  • Circular foreign key dependencies
  • Schema names with special characters
  • Case-sensitive collations

Implementation Summary:

  • āœ… Complete SchemaExtractor class with 6 extraction methods
  • āœ… 46 unit tests covering all functionality and edge cases
  • āœ… 10 integration tests with real database validation
  • āœ… Comprehensive error handling with custom exceptions
  • āœ… Metadata integrity validation with warnings
  • āœ… Example script and documentation
  • āœ… Handles NVARCHAR character length, VARCHAR(MAX), composite keys
  • āœ… Preserves column order for composite PKs/FKs
  • āœ… Detects self-referencing and circular dependencies
  • āœ… ~900 LOC implementation + ~550 LOC tests
  • āœ… Estimated coverage: 95%+

Dependencies: Story 1.1 (Connection Manager)


Story 2.2: Foreign Key Dependency Graph Builder

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 2 days

User Story:
As a developer, I want to build a dependency graph of foreign key relationships so that I can sanitize tables in the correct order without breaking integrity.

Acceptance Criteria:

  • āœ… Build directed graph of table dependencies
  • āœ… Detect circular dependencies using cycle detection algorithm
  • āœ… Perform topological sort for processing order
  • āœ… Identify self-referencing tables
  • āœ… Support composite foreign keys
  • āœ… Return processing order and cycle information

Technical Details:

  • File: src/sanitization/dependency_resolver.py
  • Graph Library: networkx 3.2.1 (Johnson's algorithm for cycles, Kahn's for topological sort)
  • Algorithms: nx.simple_cycles(), nx.topological_sort(), nx.strongly_connected_components()
  • Key Methods: get_processing_order(), get_cycles(), has_circular_dependencies(), get_dependencies(table), is_self_referencing(table)

Edge Cases:

  • Circular dependencies (Order → OrderItem → Promotion → Order)
  • Self-referencing hierarchies (Employee.ManagerID → Employee.EmployeeID)
  • Multi-level dependencies (A → B → C → D)
  • Orphaned tables (no FKs)
  • Multiple FKs between same tables

Implementation Summary:

  • āœ… Complete DependencyResolver class using networkx DiGraph
  • āœ… Graph construction from FK metadata with composite FK support (groups by constraint_name)
  • āœ… Cycle detection using Johnson's algorithm (O(V + E + C) complexity)
  • āœ… Topological sort using Kahn's algorithm (O(V + E) complexity)
  • āœ… Self-referencing table identification (separate from circular dependencies)
  • āœ… Caching of cycle detection and processing order results for performance
  • āœ… Comprehensive logging with correlation IDs and graph statistics
  • āœ… 25 unit tests covering all scenarios (simple DAG, circular, self-ref, composite FK, deep chains, edge cases)
  • āœ… 5 integration tests with real database schema creation and FK validation
  • āœ… CircularDependencyError exception with detailed cycle information and mitigation suggestions
  • āœ… Graph summary method with root/leaf tables, max depth, cycle count
  • āœ… Dependency depth calculation for multi-level hierarchies
  • āœ… Usage example demonstrating end-to-end workflow
  • āœ… ~500 LOC implementation + ~450 LOC unit tests + ~250 LOC integration tests
  • āœ… Added error codes: CIRCULAR_DEPENDENCY, INVALID_DEPENDENCY_GRAPH, TOPOLOGICAL_SORT_FAILED

Strategy for Circular FKs:

  • Raise CircularDependencyError with full cycle path and suggested mitigations
  • Let orchestrator (Story 5.2) decide: (1) disable constraints, (2) multi-stage processing, or (3) exclude tables
  • Self-referencing tables flagged separately for special handling

Dependencies: Story 2.1 (Schema Extraction)


Story 2.3: Batch Data Extractor

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 2 days

User Story:
As a developer, I want to extract data in batches so that I can process large tables without memory overflow.

Acceptance Criteria:

  • āœ… Key-based pagination (O(log n) performance)
  • āœ… Fallback to OFFSET/FETCH for tables without numeric PKs
  • āœ… Configurable batch size (default 10,000 rows)
  • āœ… Memory-efficient iterator pattern (yield)
  • āœ… Extract only PII columns (not full rows)
  • āœ… Progress tracking (rows processed / total)
  • āœ… Handle composite primary keys

Technical Details:

  • File: src/database/batch_extractor.py
  • Key Method: extract_batches(table, columns, batch_size) -> Iterator

Implementation Summary:

  • āœ… Complete BatchExtractor class with 3 pagination strategies (~800 LOC)
  • āœ… PaginationStrategy enum (KEY_BASED, COMPOSITE_KEY, ROW_NUMBER)
  • āœ… Batch dataclass with progress tracking and metadata
  • āœ… Automatic strategy selection based on PK type
  • āœ… 38 unit tests covering all scenarios and edge cases (~700 LOC)
  • āœ… Comprehensive error handling with DataExtractionError
  • āœ… Usage example demonstrating 6 common scenarios
  • āœ… SQL identifier escaping for special characters
  • āœ… Integration with existing ConnectionManager and SchemaExtractor
  • āœ… Structured logging with correlation IDs
  • āœ… NULL value handling in PII columns
  • āœ… Non-dbo schema support with fully qualified names

Pagination Strategy:

-- Key-based (FAST - preferred)
SELECT pk, pii_col1, pii_col2
FROM [schema].[table]
WHERE pk > @last_pk
ORDER BY pk
OFFSET 0 ROWS FETCH NEXT @batch_size ROWS ONLY;

-- For composite PKs or no PK
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as rn, *
FROM [schema].[table]
WHERE rn > @last_rn AND rn <= @last_rn + @batch_size;

Edge Cases:

  • Tables without primary keys
  • Composite primary keys (multi-column ordering)
  • Non-sequential primary keys (GUIDs, strings)
  • Tables with gaps in PK sequence
  • Concurrent modifications during extraction

Dependencies: Story 1.1 (Connection Manager), Story 2.1 (Schema Extraction)


Story 2.4: Batch Data Updater

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 1.5 days

User Story:
As a developer, I want to update PII values in batches so that I can efficiently sanitize large datasets.

Acceptance Criteria:

  • āœ… Batch updates using executemany or bulk operations
  • āœ… Transactional updates (commit/rollback per batch)
  • āœ… Support updating multiple columns simultaneously
  • āœ… Preserve data types during updates
  • āœ… Handle deadlocks with retry logic (SQL error 1205)
  • āœ… Parameterized queries (prevent SQL injection)

Technical Details:

  • File: src/database/batch_updater.py
  • Key Method: update_batches(schema, table, pk_columns, updates) -> Iterator[UpdateBatch]

Implementation Summary:

  • āœ… Complete BatchUpdater class with 3 update strategies (~1025 LOC)
  • āœ… UpdateStrategy enum (KEY_BASED, COMPOSITE_KEY, ROW_NUMBER)
  • āœ… UpdateBatch dataclass with progress tracking and metadata
  • āœ… Automatic strategy selection based on PK type
  • āœ… 32 unit tests covering all scenarios and edge cases (~719 LOC)
  • āœ… Deadlock retry decorator with exponential backoff
  • āœ… Transaction safety with automatic commit/rollback per batch
  • āœ… FK dependency ordering integration with DependencyResolver
  • āœ… DataUpdateError exception with detailed context
  • āœ… SQL identifier escaping for special characters
  • āœ… Integration with existing ConnectionManager and SchemaExtractor
  • āœ… Structured logging with correlation IDs
  • āœ… Multi-column updates with parameterized queries
  • āš ļø Integration tests pending

Update Strategy:

# Key-based (FAST - preferred for single numeric PK)
UPDATE [schema].[table]
SET [col1] = ?, [col2] = ?
WHERE [pk] = ?

# Composite key (for multi-column PKs)
UPDATE [schema].[table]
SET [col1] = ?, [col2] = ?
WHERE [pk1] = ? AND [pk2] = ?

Edge Cases:

  • Deadlocks during concurrent updates (retry with exponential backoff)
  • Long-running transactions causing blocking
  • FK constraint violations (must update parent first - auto-ordered)
  • Triggers that modify data
  • Computed columns (read-only)
  • Indexed columns (update performance impact)
  • Tables without primary keys (ROW_NUMBER fallback)
  • Composite primary keys (tuple-based updates)

Optimization:

  • Batch updates with configurable batch size (default: 10,000)
  • FK-aware ordering to minimize constraint violations
  • Parameterized queries for performance
  • Progress tracking with yield-based iteration
  • Memory-efficient (never loads full dataset)

Dependencies: Story 1.1 (Connection Manager), Story 2.1 (Schema Extraction), Story 2.2 (Dependency Resolver)


Story 2.5: Transaction & Rollback Manager

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 1 day

User Story:
As a developer, I want transaction management with rollback capability so that I can recover from failures without data corruption.

Acceptance Criteria:

  • āœ… Begin/commit/rollback transactions
  • āœ… Savepoint support for nested operations
  • āœ… Automatic rollback on exceptions
  • āœ… Context manager pattern for clean syntax
  • āœ… Audit trail of all transactions

Technical Details:

  • File: src/database/transaction_manager.py
  • Key Methods: begin(), commit(), rollback(), begin_savepoint(), rollback_to_savepoint()
  • Pattern: Context manager (with transaction_manager.begin())

Implementation Summary:

  • āœ… Complete TransactionManager class with savepoint support (~647 LOC)
  • āœ… IsolationLevel enum (READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE, SNAPSHOT)
  • āœ… TransactionAudit dataclass for complete lifecycle tracking
  • āœ… Context manager pattern for automatic commit/rollback
  • āœ… Nested transaction support via SQL Server savepoints (up to 32 levels)
  • āœ… Rollback hooks for compensation logic (LIFO execution)
  • āœ… Configurable transaction timeout with automatic rollback
  • āœ… Thread-safe state management with threading.Lock
  • āœ… Audit history with configurable retention (default: 1000 transactions)
  • āœ… TransactionError exception with detailed context
  • āœ… Structured logging with correlation IDs
  • āœ… Integration with ConnectionManager
  • āœ… Savepoint name validation (alphanumeric + underscore only)
  • āš ļø Unit tests pending
  • āš ļø Integration tests pending

Usage Example:

with transaction_manager.begin():
    # Operations auto-commit on success
    # Auto-rollback on exception
    updater.update_batch(table, data)

# Nested transactions with savepoints
with transaction_manager.begin():
    updater.update_batch(table1, data1)
    with transaction_manager.begin():  # Creates savepoint
        updater.update_batch(table2, data2)
        # Auto-rolls back to savepoint on exception

Edge Cases:

  • Nested transactions (uses savepoints, max depth: 32)
  • Distributed transactions (not supported - single DB only)
  • Long-running transactions timing out (configurable timeout)
  • Connection failures mid-transaction (automatic rollback)
  • Invalid savepoint names (validated against pattern)
  • Savepoint depth exceeded (raises TransactionError)
  • Concurrent transaction state access (thread-safe with locks)

Dependencies: Story 1.1 (Connection Manager), Story 1.3 (Logging)


PHASE 3: AI Integration & User Interaction (3 Stories)

Story 3.1: GitHub Copilot API Client

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 1.5 days

User Story:
As a developer, I want to integrate with GitHub Copilot API so that I can automatically detect PII columns.

Acceptance Criteria:

  • āœ… Send schema metadata JSON to Copilot API
  • āœ… Parse AI response for PII recommendations
  • āœ… Handle API failures gracefully (retry, fallback)
  • āœ… Rate limiting and quota management
  • āœ… Secure API authentication (env variables)
  • āœ… Cache responses to avoid duplicate API calls

Technical Details:

  • File: src/ai/copilot_client.py
  • API: GitHub Copilot Model API
  • Key Method: detect_pii(schema_json) -> List[PIIColumn]

Implementation Summary:

  • āœ… Complete CopilotClient class with retry logic and caching (~700 LOC)
  • āœ… Pydantic models for request/response validation (PIIColumn, PIIDetectionResponse)
  • āœ… Prompt engineering templates with few-shot examples
  • āœ… Exponential backoff retry decorator handling timeouts, network errors, rate limits
  • āœ… Response caching with SHA256 key generation and TTL expiration
  • āœ… Batch processing for large schemas (50 tables per request)
  • āœ… AIConfig model integrated into SanitizationConfig
  • āœ… Environment-based API key authentication (GITHUB_COPILOT_API_KEY)
  • āœ… 40+ unit tests covering retry logic, caching, error handling, edge cases
  • āœ… 10 integration tests with workflow validation
  • āœ… Example script demonstrating end-to-end usage
  • āœ… ~2000 LOC implementation + tests + examples
  • āœ… Error codes: AI_API_REQUEST_FAILED, AI_API_TIMEOUT, AI_API_QUOTA_EXCEEDED, AI_AUTH_FAILED, AI_NETWORK_ERROR, AI_INVALID_RESPONSE
  • āœ… Exception classes: AIServiceError, APIRequestError, APIResponseError

Prompt Template:

Analyze this database schema and identify columns that likely contain PII.
For each PII column, specify the type (email, phone, name, ssn, etc.).

Schema:
{schema_json}

Return JSON format:
{
  "pii_columns": [
    {"schema": "dbo", "table": "Customers", "column": "Email", "pii_type": "email"},
    ...
  ]
}

Edge Cases:

  • API quota exceeded (429 error)
  • Network timeouts
  • Invalid JSON responses
  • Ambiguous column names ("Data", "Info")
  • False positives ("EmailTemplate" is not PII)

Dependencies: Story 2.1 (Schema Extraction)


Story 3.2: User Review Interface (CLI)

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 1 day

User Story:
As a user, I want to review and modify AI-detected PII columns so that I can ensure accuracy before sanitization.

Acceptance Criteria:

  • āœ… Display AI recommendations in formatted table
  • āœ… Allow adding new PII columns
  • āœ… Allow removing false positives
  • āœ… Allow changing PII type (email → phone)
  • āœ… Validate columns exist in schema
  • āœ… Save finalized config to JSON

Technical Details:

  • File: src/ui/review_cli.py
  • Library: rich for formatted tables
  • Output: config/pii_config.json

Implementation Summary:

  • āœ… PIIReviewCLI class with interactive menu-driven interface
  • āœ… Rich terminal formatting with tables, panels, and color coding
  • āœ… Add, remove, modify operations with validation
  • āœ… Undo functionality for all operations
  • āœ… Schema validation with FK/PK warnings
  • āœ… Configuration persistence to JSON
  • āœ… 50+ unit tests + 15 integration tests
  • āœ… Comprehensive example script (examples/review_cli_example.py)

CLI Interface:

AI Recommended PII Columns:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Schema.Table          Column        Type
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
dbo.Customers         Email         email
dbo.Customers         Phone         phone
dbo.Employees         SSN           ssn

Options:
[A]dd  [R]emove  [M]odify  [S]ave  [Q]uit

Dependencies: Story 3.1 (AI Client), Story 2.1 (Schema Extraction)


Story 3.3: Configuration Schema Validator

Status: āœ… Completed
Priority: MEDIUM
Estimated Effort: 1 day

User Story:
As a developer, I want to validate PII configuration files so that I catch errors before sanitization begins.

Acceptance Criteria:

  • āœ… Validate JSON structure with Pydantic
  • āœ… Check all columns exist in database
  • āœ… Verify data types compatible with masking strategy
  • āœ… Warn about missing nullable constraints
  • āœ… Validate FK dependencies
  • āœ… Clear error messages for validation failures

Implementation Details:

  • Files:
    • src/validation/validation_result.py (ValidationResult, ValidationIssue, IssueSeverity)
    • src/validation/config_validator.py (ConfigValidator with comprehensive validation logic)
    • examples/validate_config_example.py (Example usage with color-coded output)
    • tests/unit/test_validation_result.py (40+ unit tests)
    • tests/unit/test_config_validator.py (30+ unit tests)
    • tests/integration/test_config_validator_integration.py (Integration tests)
  • Key Methods:
    • ConfigValidator.validate_config(config) -> ValidationResult
    • ConfigValidator.validate_single_column(pii_column) -> ValidationResult
  • Validation Checks:
    • Column existence (schema, table, column)
    • Data type compatibility (PII type → SQL type mapping)
    • Nullable constraints (config vs database)
    • Special columns (PKs, FKs, identity, computed, system tables, temp tables, views)
    • Column length sufficiency (prevent silent truncation)
  • Error Codes: Added 16 validation error codes to error_codes.py
  • Edge Cases Handled:
    • System schemas (sys, INFORMATION_SCHEMA)
    • Temp tables (# prefix)
    • Identity and computed columns
    • Insufficient column lengths
    • CHAR vs VARCHAR warnings

Pydantic Model:

class PIIColumn(BaseModel):
    schema: str
    table: str
    column: str
    pii_type: Literal["email", "phone", "name", "ssn", "generic"]
    nullable: bool
    custom_format: Optional[str] = None

Dependencies: Story 1.2 (Config Management), Story 2.1 (Schema Extraction)


PHASE 4: Data Masking Engine (6 Stories)

Story 4.1: Base Masker Abstract Class

Status: āœ… Completed
Priority: CRITICAL
Estimated Effort: 1 day

User Story:
As a developer, I want a base masker interface so that I can implement consistent masking strategies.

Acceptance Criteria:

  • āœ… Abstract mask() method
  • āœ… Deterministic masking (same input → same output)
  • āœ… Type safety with data type validation
  • āœ… Length constraint enforcement
  • āœ… Null handling strategy (preserve/mask/randomize)

Technical Details:

  • File: src/masking/base_masker.py
  • Pattern: Abstract Base Class (ABC)
  • Key Methods: mask(), _get_deterministic_seed(), _validate_length(), _handle_null()

Implementation Summary:

  • āœ… Complete BaseMasker abstract base class (~440 LOC)
  • āœ… MaskingStrategy enum (PRESERVE, MASK, RANDOMIZE)
  • āœ… ColumnInfo dataclass with comprehensive SQL Server type metadata
  • āœ… SHA256-based deterministic seed generation
  • āœ… Intelligent length validation with Unicode awareness
  • āœ… Data type validation before returning values
  • āœ… NULL handling with configurable strategy
  • āœ… Fixed-length column padding (CHAR, NCHAR)
  • āœ… VARCHAR(MAX) support with reasonable defaults
  • āœ… MaskingError exception with detailed context
  • āœ… 54 unit tests covering all functionality
  • āœ… Comprehensive logging with correlation IDs
  • āœ… Integration with SchemaExtractor metadata
  • āœ… Support for NVARCHAR character length vs byte length

Interface:

class BaseMasker(ABC):
    def __init__(
        self, 
        seed: int = 42,
        null_strategy: MaskingStrategy = MaskingStrategy.PRESERVE,
        logger: Optional[logging.Logger] = None
    ):
        self.seed = seed
        self.null_strategy = null_strategy
        self.logger = logger or get_logger(self.__class__.__name__)
    
    @abstractmethod
    def mask(self, value: Any, column_info: ColumnInfo) -> Any:
        """Mask a single value deterministically."""
        pass
    
    def _get_deterministic_seed(self, value: Any) -> int:
        """Generate deterministic seed using SHA256 hash."""
        pass
    
    def _validate_length(self, value: str, column_info: ColumnInfo) -> str:
        """Validate and truncate to max_length with Unicode awareness."""
        pass
    
    def _handle_null(self, value: Any, column_info: ColumnInfo) -> Any:
        """Handle NULL values based on null_strategy."""
        pass

Determinism: SHA256 hash of original value combined with global seed ensures same input → same output


Story 4.2: Email Masker

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 0.5 days

User Story:
As a developer, I want to mask email addresses so that I can anonymize contact information.

Acceptance Criteria:

  • āœ… Generate valid email format
  • āœ… Preserve domain diversity (not all @example.com)
  • āœ… Deterministic (same email → same fake email)
  • āœ… Respect max_length constraints
  • āœ… Handle international domains

Technical Details:

  • File: src/masking/email_masker.py
  • Key Methods: mask(), _generate_email(), _validate_email_format(), _select_domain()
  • Strategy: Hash email → user_{hash8}@{domain} with deterministic domain selection

Implementation Summary:

  • āœ… Complete EmailMasker class extending BaseMasker (~350 LOC)
  • āœ… 10-domain pool for diversity (example.com, test.org, demo.net, sample.io, fake.email, masked.dev, sanitized.app, placeholder.co, dummy.tech, anon.site)
  • āœ… Multi-tier length optimization (Standard ~26 chars → Compact ~18 chars → Minimal 6 chars)
  • āœ… SHA256-based deterministic seeding from BaseMasker
  • āœ… RFC 5322 email format validation
  • āœ… 55 unit tests covering all scenarios and edge cases (~560 LOC)
  • āœ… Comprehensive example script with 8 scenarios (~280 LOC)
  • āœ… Unicode/IDN domain support for NVARCHAR columns
  • āœ… VARCHAR vs NVARCHAR handling (ASCII vs Unicode)
  • āœ… Fixed-length column padding (CHAR, NCHAR)
  • āœ… Special format handling (IP domains, quoted strings, whitespace)
  • āœ… NULL handling strategies (PRESERVE, MASK)
  • āœ… Integration with BaseMasker interface
  • āœ… Deterministic mapping ensures FK integrity

Domain Pool:

DOMAINS = [
    "example.com", "test.org", "demo.net", "sample.io",
    "fake.email", "masked.dev", "sanitized.app", "placeholder.co",
    "dummy.tech", "anon.site"
]

Generation Algorithm:

  1. Get deterministic seed from input email
  2. Generate username: user_{hash8} (8-char hex from seed)
  3. Select domain: DOMAINS[seed % len(DOMAINS)]
  4. Combine: {username}@{domain}
  5. Optimize length if needed (multi-tier fallback)
  6. Validate and return

Length Optimization:

  • Standard: user_a1b2c3d4@example.com (~26 chars)
  • Compact: u_a1b2c3@demo.co (~18 chars)
  • Minimal: x@y.co (6 chars minimum)

Edge Cases Handled:

  • IP address domains: user@[192.168.1.1] → replaced with standard domain
  • Quoted local-parts: "user@test"@example.com → standard format
  • Whitespace: Leading/trailing spaces trimmed
  • Case sensitivity: Different cases → different hashes → different outputs
  • Very long emails: Truncated while preserving @domain structure
  • Consecutive dots: Masked with warning logged
  • Invalid formats: Masked anyway (AI might false-positive detect)
  • Unicode characters: Handled for NVARCHAR columns
  • NULL values: PRESERVE (returns None) or MASK (generates fake email)

Example:

masker = EmailMasker(seed=42)
col = ColumnInfo(data_type="VARCHAR", max_length=50, nullable=True)
masked = masker.mask("john.doe@gmail.com", col)
# Returns: user_a1b2c3d4@example.com (deterministic)

Dependencies: Story 4.1 (Base Masker)


Story 4.3: Phone Number Masker

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 1 day

User Story:
As a developer, I want to mask phone numbers so that I can anonymize telecommunications data.

Acceptance Criteria:

  • āœ… Generate valid phone formats
  • āœ… Multi-tier length optimization (standard, compact, minimal)
  • āœ… Deterministic masking
  • āœ… Handle various formats (10-digit, +country code, extensions)
  • āœ… Respect max_length

Technical Details:

  • File: src/masking/phone_masker.py
  • Key Methods: mask(), _generate_phone(), _validate_phone_format(), _get_format_tier()
  • Strategy: Deterministic digit generation using modulo arithmetic with fixed 555 area code (reserved/fictional)

Implementation Summary:

  • āœ… Complete PhoneMasker class extending BaseMasker (~470 LOC)
  • āœ… Fixed 555 area code (reserved for fictional use in North America)
  • āœ… Multi-tier length optimization (Standard 14 chars → Compact 12 → Minimal 10)
  • āœ… SHA256-based deterministic seeding from BaseMasker
  • āœ… Modulo arithmetic for digit generation (predictable, testable)
  • āœ… 61 unit tests covering all scenarios and edge cases (~700 LOC)
  • āœ… Comprehensive example script with 9 scenarios including batch masking (~400 LOC)
  • āœ… US and international phone format validation
  • āœ… VARCHAR vs NVARCHAR handling (ASCII vs Unicode)
  • āœ… Fixed-length column padding (CHAR, NCHAR)
  • āœ… Special format handling (extensions, international prefixes, invalid formats)
  • āœ… NULL handling strategies (PRESERVE, MASK)
  • āœ… Integration with BaseMasker interface
  • āœ… Deterministic mapping ensures FK integrity

Phone Format Tiers:

# Standard (14+ chars): (555) 555-5555
# Compact (12-13 chars): 555-555-5555
# Minimal (10-11 chars): 5555555555
# Error (<10 chars): Raise MaskingError

Generation Algorithm:

  1. Extract deterministic seed from input phone
  2. Generate exchange (middle 3 digits): ((seed // 10000) % 900) + 100 (range 100-999)
  3. Generate subscriber (last 4 digits): (seed % 9000) + 1000 (range 1000-9999)
  4. Combine with fixed 555 area code
  5. Format based on column length constraints
  6. Validate and return

Length Optimization:

  • Standard: (555) 555-5555 (14 characters)
  • Compact: 555-555-5555 (12 characters)
  • Minimal: 5555555555 (10 characters)

Edge Cases Handled:

  • Whitespace: Leading/trailing spaces trimmed
  • Extensions: Ignored in masking (e.g., "ext. 123")
  • Very long numbers: Truncated to fit column constraints
  • International prefixes: Recognized but output uses US format
  • Special characters: Stripped from generated output
  • Invalid formats: Masked anyway (AI may have false positives)
  • Plain digits: Accepted and masked
  • NULL values: PRESERVE (returns None) or MASK (generates fake phone)
  • Column too short (<10 chars): Raises MaskingError with actionable message

Supported Input Formats:

  • US standard: (555) 123-4567, 555-123-4567, 555.123.4567
  • Plain digits: 5551234567
  • International: +1-555-123-4567, +44 20 1234 5678
  • With extensions: 555-123-4567 ext. 123 (extension ignored)

Example:

masker = PhoneMasker(seed=42)
col = ColumnInfo(data_type="VARCHAR", max_length=20, nullable=True)
masked = masker.mask("(555) 123-4567", col)
# Returns: (555) 512-2345 (deterministic, 14 chars)

compact_col = ColumnInfo(data_type="VARCHAR", max_length=12, nullable=True)
masked_compact = masker.mask("5551234567", compact_col)
# Returns: 555-512-2345 (compact format, 12 chars)

Dependencies: Story 4.1 (Base Masker)


Story 4.4: Name Masker

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 0.5 days

User Story:
As a developer, I want to mask personal names so that I can anonymize identity information.

Acceptance Criteria:

  • āœ… Generate realistic fake names using Faker library
  • āœ… Preserve gender consistency (optional)
  • āœ… Deterministic mapping (same name → same fake name)
  • āœ… Support first, last, and full names
  • āœ… Handle Unicode names (internationalization)

Technical Details:

  • File: src/masking/name_masker.py
  • Library: faker==19.12.0
  • Strategy: Seed Faker with hash of original name for deterministic generation
  • MIN_LENGTH: 2 characters (supports single-letter names like "Li", "Wu")

Implementation Summary:

  • āœ… Complete NameMasker class with Faker integration (~570 LOC)
  • āœ… Multi-tier length optimization:
    • Full (20+ chars): "Dr. John Smith Jr." with prefix/suffix
    • First+Last (10-19 chars): "John Smith"
    • First Only (4-9 chars): "John"
    • Initial (2-3 chars): "J" or "JS"
  • āœ… Name structure detection (prefixes, suffixes, hyphenation)
  • āœ… Unicode support for international names (JosĆ©, FranƧois, Ꝏ꘎)
  • āœ… Format validation with warning logs for invalid inputs
  • āœ… Deterministic seed generation from input hash
  • āœ… 61 comprehensive unit tests (100% pass rate)
  • āœ… Usage example with 8 practical scenarios
  • āœ… MIN_LENGTH validator added to config_validator.py
  • āœ… Exported from src/masking/init.py

Test Coverage:

  • āœ… 6 tests for basic masking (deterministic, seed independence)
  • āœ… 10 tests for length tiers and boundaries
  • āœ… 16 tests for name structure (prefixes, suffixes, hyphenation)
  • āœ… 6 tests for data types (VARCHAR, NVARCHAR, CHAR, TEXT)
  • āœ… 4 tests for NULL handling strategies
  • āœ… 9 tests for validation and error handling
  • āœ… 10 tests for edge cases (Unicode, apostrophes, special characters)

Edge Cases Handled:

  • Hyphenated names (Mary-Jane, Jean-Pierre)
  • Prefixes/suffixes (Dr., Mr., Jr., III)
  • Names with apostrophes (O'Brien)
  • Unicode characters (JosĆ© GarcĆ­a, Ꝏ꘎, ē”°äø­)
  • Very long names with multiple components
  • Invalid formats (logs warning but continues masking)
  • Single-letter names at minimum length (2 chars)
  • Excessive whitespace trimming

Dependencies: Story 4.1 (Base Masker)


Story 4.5: SSN Masker

Status: āœ… Completed
Priority: MEDIUM
Estimated Effort: 0.5 days

User Story:
As a developer, I want to mask Social Security Numbers so that I can anonymize government identifiers.

Acceptance Criteria:

  • āœ… Generate valid SSN format (XXX-XX-XXXX)
  • āœ… Avoid real SSN ranges (exclude 666, 900+)
  • āœ… Deterministic
  • āœ… Support plain (9-digit) and formatted versions

Technical Details:

  • File: src/masking/ssn_masker.py
  • Valid Ranges: 001-665, 667-899 (excludes 000, 666, 900-999)
  • Format: f"{area:03d}-{group:02d}-{serial:04d}" (formatted) or plain 9 digits
  • MIN_LENGTH: 9 characters (plain format)

Implementation Summary:

  • āœ… Complete SSNMasker class with compliance validation (~380 LOC)
  • āœ… Multi-format support:
    • Formatted (11+ chars): "123-45-6789" (XXX-XX-XXXX)
    • Plain (9-10 chars): "123456789" (9 digits)
  • āœ… Valid area code generation with gap handling (001-665, 667-899)
  • āœ… Modulo arithmetic for deterministic generation
  • āœ… Format detection and auto-selection
  • āœ… 45 comprehensive unit tests (100% pass rate)
  • āœ… Usage example with 8 practical scenarios
  • āœ… MIN_LENGTH and data type validators verified in config_validator.py
  • āœ… Exported from src/masking/init.py

Test Coverage:

  • āœ… 6 tests for basic masking (deterministic, seed independence)
  • āœ… 9 tests for format detection and handling
  • āœ… 7 tests for valid SSN ranges (area/group/serial)
  • āœ… 5 tests for invalid range exclusion (000, 666, 900-999)
  • āœ… 6 tests for data types (VARCHAR, NVARCHAR, CHAR, TEXT)
  • āœ… 4 tests for NULL handling strategies
  • āœ… 9 tests for validation and error handling
  • āœ… 6 tests for edge cases (whitespace, boundaries, distribution)

Edge Cases Handled:

  • Invalid area codes excluded (000, 666, 900-999) via modulo with gap handling
  • Both formatted (XXX-XX-XXXX) and plain (9 digits) input/output formats
  • Column too short (<9 chars) raises clear MaskingError
  • Invalid format logs warning but continues masking (AI false positives)
  • Fixed-length columns (CHAR, NCHAR) padded appropriately
  • Whitespace trimming before processing
  • Deterministic mapping across both valid ranges (001-665, 667-899)

Dependencies: Story 4.1 (Base Masker)


Story 4.6: Generic String Masker

Status: āœ… COMPLETE
Priority: LOW
Estimated Effort: 0.5 days
Actual Effort: 0.5 days
Completed: 2026-03-26

User Story:
As a developer, I want a fallback masker for unknown PII types so that I can handle custom or miscellaneous fields.

Acceptance Criteria:

  • āœ… Generate random alphanumeric strings
  • āœ… Preserve original length (or respect max_length)
  • āœ… Deterministic
  • āœ… Support character classes (alpha, numeric, alphanumeric)

Technical Details:

  • File: src/masking/generic_masker.py (330 LOC)
  • Tests: tests/unit/test_generic_masker.py (44 tests)
  • Example: examples/generic_masking_example.py
  • Strategy: Modulo arithmetic for character-by-character generation
  • Character Classes: alphanumeric (default), alpha, numeric
  • Minimum Length: 1 (most permissive of all maskers)

Implementation Notes:

  • Simple length preservation (no multi-tier formatting)
  • Supports any string length >= 1
  • Deterministic using (seed + i) % len(charset)
  • Three character sets: ALPHANUMERIC_CHARS (62), ALPHA_CHARS (52), NUMERIC_CHARS (10)
  • Ideal for custom PII types, miscellaneous fields, reference codes

Dependencies: Story 4.1 (Base Masker)


PHASE 5: Orchestration & Execution (5 Stories)

Story 5.1: Masking Strategy Factory

Status: āœ… COMPLETE
Priority: MEDIUM
Estimated Effort: 0.5 days
Actual Effort: 0.5 days
Completed: 2026-03-26

User Story:
As a developer, I want a factory to instantiate maskers so that I can dynamically select strategies based on PII type.

Acceptance Criteria:

  • āœ… Map PII types to masker classes
  • āœ… Support custom maskers via configuration
  • āœ… Raise clear errors for unknown types
  • āœ… Singleton pattern for masker reuse

Technical Details:

  • File: src/masking/masker_factory.py (450 LOC)
  • Tests: tests/unit/test_masker_factory.py (43 tests)
  • Example: examples/masker_factory_example.py
  • Pattern: Registry + Factory with thread-safe singleton
  • Registry: Maps 5 built-in PII types to masker classes
  • Caching: Automatic caching for performance (same config = same instance)
  • Thread Safety: Double-checked locking pattern for concurrent access

Implementation Notes:

  • Thread-safe singleton following ConfigLoader pattern
  • Cache key includes: pii_type, seed, null_strategy, masker_params
  • Supports masker-specific parameters via PIIColumnConfig.custom_format
  • GenericMasker character_class extraction: "alpha", "numeric", "alphanumeric"
  • Custom masker registration via register_masker() method
  • Clear error handling with MaskingError.unsupported_pii_type() and masker_not_found()
  • Manual cache clearing for testing/cleanup via clear_cache()

Registry:

_registry = {
    "email": EmailMasker,
    "phone": PhoneMasker,
    "name": NameMasker,
    "ssn": SSNMasker,
    "generic": GenericMasker,
}

Dependencies: Stories 4.1-4.6 (All Maskers)


Story 5.2: Sanitization Orchestrator

Status: āœ… COMPLETE
Priority: CRITICAL
Estimated Effort: 3 days
Actual Effort: 3 days

User Story:
As a developer, I want a central orchestrator so that I can coordinate the entire sanitization workflow.

Acceptance Criteria:

  • āœ… Execute workflow steps in correct order
  • āœ… Handle FK dependencies (parent before child)
  • āœ… Support dry-run mode (validation only)
  • āœ… Progress reporting (tables/rows processed)
  • āœ… Comprehensive error handling
  • āœ… Resume from checkpoint on failure

Technical Details:

  • File: src/sanitization/orchestrator.py (800 LOC)
  • Key Method: run(config, dry_run=False) -> SanitizationReport
  • Tests: tests/unit/test_orchestrator.py (82 tests)
  • Examples: examples/orchestrator_example.py (8 examples)

Workflow:

  1. Validate configuration
  2. Build dependency graph
  3. Topologically sort tables
  4. For each table (parent → child):
    • Extract batch
    • Mask values
    • Store mapping
    • Update database
  5. Validate integrity

Implementation Notes:

  • 4 execution phases: Validation → Planning → Execution → Verification
  • Batch processing with memory-efficient generators
  • Per-table transactions for partial completion support
  • Checkpoint/resume mechanism with JSON serialization
  • Progress callbacks for table-level and batch-level tracking
  • Dry-run mode validates without database modifications
  • Comprehensive error handling with retryable errors
  • Correlation ID tracking throughout execution
  • SanitizationReport with detailed statistics and per-table progress

Dependencies: All previous stories


Story 5.3: Mapping Table Manager

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 2 days
Actual Effort: 2 days
Completed: 2026-03-27

User Story:
As a developer, I want to store original→fake value mappings so that I can trace changes and support desensitization.

Acceptance Criteria:

  • āœ… Create mapping table on first run
  • āœ… Store schema, table, column, original, fake values
  • āœ… Store timestamps and operation IDs
  • āœ… Support encryption of original values (Fernet AES-128)
  • āœ… Efficient lookup for desensitization
  • āœ… Batch inserts for performance

Technical Details:

  • Files:
    • src/mapping/mapping_manager.py (āœ… Complete - ~1025 LOC)
    • src/mapping/mapping_models.py (āœ… Complete - MappingEntry, MappingBatch, MappingStats)
    • src/mapping/mapping_config.py (āœ… Complete - MappingConfig Pydantic model)
    • src/mapping/encryption_utils.py (āœ… Complete - EncryptionManager)
  • Table: sanitization.pii_mappings (configurable schema/table name)

Schema:

CREATE TABLE [sanitization].[pii_mappings] (
    mapping_id BIGINT IDENTITY(1,1) PRIMARY KEY,
    operation_id UNIQUEIDENTIFIER NOT NULL,
    schema_name NVARCHAR(128) NOT NULL,
    table_name NVARCHAR(128) NOT NULL,
    column_name NVARCHAR(128) NOT NULL,
    original_value_hash VARBINARY(32) NOT NULL,
    original_value_encrypted VARBINARY(MAX),
    masked_value NVARCHAR(MAX),
    data_type NVARCHAR(128) NOT NULL,
    is_null BIT NOT NULL DEFAULT 0,
    created_at DATETIME2 DEFAULT GETUTCDATE(),
    INDEX idx_lookup (schema_name, table_name, column_name, original_value_hash),
    INDEX idx_operation (operation_id)
);

Implementation Summary:

  • āœ… MappingManager fully implemented with idempotent schema/table/index creation
  • āœ… Batch storage with configurable batch sizes (100-100,000 rows)
  • āœ… Deadlock retry with exponential backoff (@retry_on_deadlock decorator)
  • āœ… Entry retrieval (by operation, table, column, filtered)
  • āœ… Operation statistics aggregation (MappingStats)
  • āœ… Encryption support using Fernet (AES-128-CBC + HMAC)
  • āœ… Environment-based encryption key management
  • āœ… Thread-safe operations with connection pooling
  • āœ… Integrated into Orchestrator workflow (automatic mapping during sanitization)
  • āœ… Comprehensive unit tests (~100% coverage with mocks)
  • āœ… Integration tests with real SQL Server database
  • āœ… Edge case validation (Unicode, NULL values, special characters, large batches)
  • āœ… Example scripts demonstrating usage patterns
  • āœ… Updated orchestrator_example.py with mapping storage example

Testing:

  • āœ… Unit tests: tests/unit/test_mapping_manager.py
  • āœ… Integration tests: tests/integration/test_mapping_manager_integration.py
  • āœ… Orchestrator integration: tests/integration/test_orchestrator_mapping_integration.py
  • āœ… Edge case tests: tests/integration/test_mapping_edge_cases.py
  • āœ… Test helpers: tests/integration/mapping_test_helpers.py

Examples:

  • āœ… Standalone usage: examples/mapping_example.py (6 examples)
  • āœ… Orchestrator integration: examples/orchestrator_example.py (Example 9)

Configuration:

mapping=MappingConfig(
    enabled=True,
    schema_name="sanitization",
    table_name="pii_mappings",
    encryption_enabled=False,  # Set True for production
    batch_size=10000,
    index_creation=True,
    transactional=True
)

Encryption Setup:

from src.mapping.encryption_utils import EncryptionManager
import os

# Generate key
key = EncryptionManager.generate_key()
os.environ['SANITIZATION_MAPPING_ENCRYPTION_KEY'] = key

Performance:

  • Batch storage: ~10,000+ entries/second (with indexing)
  • Concurrent writes: Deadlock-safe with automatic retry
  • Large batches: Successfully tested with 100,000+ rows

Dependencies: Story 1.1 (Connection Manager), Story 5.2 (Orchestrator)


Story 5.4: Desensitization (Reverse) Engine

Status: āœ… Completed
Priority: MEDIUM
Estimated Effort: 1.5 days

User Story:
As a developer, I want to restore original values so that I can reverse sanitization if needed.

Acceptance Criteria:

  • āœ… Read mappings from mapping table
  • āœ… Replace fake values with original values
  • āœ… Support selective restore (specific tables/columns)
  • āœ… Validate mappings exist before restoring
  • āœ… Transactional restore

Technical Details:

  • File: src/sanitization/desensitizer.py
  • Key Method: restore(operation_id, tables=None) -> RestoreReport

Implementation Summary:

  • āœ… Complete Desensitizer class with phased workflow (~900 LOC)
  • āœ… RestorePhase enum (VALIDATION, PLANNING, RESTORATION, VERIFICATION, COMPLETED, FAILED)
  • āœ… RestoreBatch, TableRestoreProgress, RestoreReport dataclasses
  • āœ… DesensitizationConfig with validation (max_mismatch_percentage, sample_size_for_validation)
  • āœ… Dependency injection pattern for all components
  • āœ… Phase 1: Validation (operation exists, mappings complete, encryption key available)
  • āœ… Phase 2: Planning (reverse FK dependency order: child → parent)
  • āœ… Phase 3: Restoration (batch processing with per-table savepoints)
  • āœ… Phase 4: Verification (integrity checks)
  • āœ… Dry-run mode for safety testing
  • āœ… Partial restore support (specific tables)
  • āœ… Progress tracking callbacks (batch and table level)
  • āœ… Encryption/decryption roundtrip
  • āœ… Transaction safety with automatic rollback
  • āœ… Comprehensive error handling
  • āœ… Correlation IDs for audit trails
  • āœ… Unit tests (~600 LOC, 40+ test cases)
  • āœ… Integration tests (~750 LOC, test database setup, E2E workflows)
  • āœ… Examples (~650 LOC, 8 usage scenarios)

Usage Example:

# Basic full restoration
desensitizer = Desensitizer(
    connection_manager=conn_mgr,
    mapping_manager=mapping_mgr
)
report = desensitizer.restore(operation_id)
print(f"Restored {report.rows_restored} rows from {report.tables_restored} tables")

# Dry-run mode
report = desensitizer.restore(operation_id, dry_run=True)

# Partial restore
report = desensitizer.restore(
    operation_id,
    tables=["dbo.Customers", "dbo.Orders"]
)

# With progress tracking
def progress(table, rows, total, pct):
    print(f"[{table}] {pct:.1f}% complete")

desensitizer.set_progress_callback(progress)
report = desensitizer.restore(operation_id)

Workflow (Implemented):

  1. Phase 1 - Validation: Verify operation exists, mappings complete, encryption key available
  2. Phase 2 - Planning: Build reverse FK dependency graph (child → parent order)
  3. Phase 3 - Restoration: Decrypt original values, update database in batches with savepoints
  4. Phase 4 - Verification: Validate integrity (row counts, FK consistency)

Edge Cases Handled:

  • Operation not found (DesensitizationError)
  • Missing encryption key (DesensitizationError)
  • Partial restore disabled (warning, falls back to full)
  • Circular FK dependencies (warning, continues processing)
  • Table restoration failures (per-table savepoints, continues with others)
  • Decryption failures (DesensitizationError with context)
  • NULL value handling
  • Empty mapping sets (skips table with warning)

Dependencies: Story 5.3 (Mapping Manager), Story 2.4 (Batch Updater)


Story 5.5: Pre/Post Sanitization Validator

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 2 days

User Story:
As a developer, I want to validate data integrity before and after sanitization so that I can ensure no data corruption occurs.

Acceptance Criteria:

  • āœ… Pre-sanitization: row counts, NULL counts, FK integrity
  • āœ… Post-sanitization: row counts unchanged, data types preserved
  • āœ… Validate no PII remains (regex pattern matching)
  • āœ… Validate FK relationships intact
  • āœ… Generate validation report (JSON/HTML)

Technical Details:

  • File: src/validation/integrity_validator.py
  • Methods: validate_pre(), validate_post(), compare_snapshots()

Implementation Summary:

  • āœ… ValidationPhase enum (PRE_SANITIZATION, POST_SANITIZATION, PRE_DESENSITIZATION, POST_DESENSITIZATION)
  • āœ… ValidationConfig dataclass with configurable thresholds and PII whitelists (~100 LOC)
  • āœ… Enhanced TableMetrics with column_max_lengths, identity_columns, computed_columns
  • āœ… Enhanced IntegrityReport with row_count_deltas, null_count_deltas, data_type_mismatches, FK changes
  • āœ… IntegrityReport.to_json() - JSON export with ISO timestamps
  • āœ… IntegrityReport.to_html() - Styled HTML report with CSS, collapsible sections, charts (~300 LOC)
  • āœ… IntegrityReport.export() - Unified export (JSON/HTML/both)
  • āœ… IntegrityReport.has_critical_issues() - Critical error detection
  • āœ… IntegrityReport.severity_summary() - Issue count by severity
  • āœ… _validate_fk_constraint_existence() - FK constraint verification
  • āœ… _validate_composite_fk_integrity() - Multi-column FK validation with NULL handling
  • āœ… _validate_circular_fk_dependencies() - Cycle detection via DependencyResolver
  • āœ… _validate_self_referencing_tables() - Hierarchical data validation
  • āœ… _validate_row_count_with_sampling() - Large table sampling support
  • āœ… _validate_column_length_preservation() - Truncation detection (MAX(LEN()) comparison)
  • āœ… _validate_null_preservation_strategy() - Per-column NULL delta calculation
  • āœ… _validate_data_type_precision() - NUMERIC_PRECISION/SCALE validation
  • āœ… _validate_pii_patterns_with_whitelist() - Whitelist/exception handling for PII patterns
  • āœ… _validate_masking_effectiveness() - Effectiveness score calculation (95% threshold)
  • āœ… _compare_pii_patterns_pre_post() - Pre vs post PII pattern comparison

Validation Checks:

  • āœ… Row count consistency (exact or sampled)
  • āœ… NULL value preservation (per-column delta %)
  • āœ… Data type preservation (schema integrity)
  • āœ… FK relationship integrity (no orphans, composite FK support)
  • āœ… PII pattern detection (EMAIL, PHONE, SSN, CREDIT_CARD with whitelist)
  • āœ… Column length preservation (truncation detection)
  • āœ… Numeric precision/scale preservation
  • āœ… FK constraint existence (detect dropped constraints)
  • āœ… Circular FK dependency detection
  • āœ… Self-referencing table validation

Report Generation:

  • āœ… JSON format: Machine-readable, automation-friendly, schema versioned
  • āœ… HTML format: Human-readable with CSS styling, color-coded severity (red=error, yellow=warning, green=success)
  • āœ… Collapsible sections with JavaScript for expand/collapse
  • āœ… Row count comparison table with delta badges
  • āœ… Execution metrics display (pre/post snapshot duration)
  • āœ… Export to ./validation_reports/ directory with timestamp
  • āœ… Correlation IDs for audit trail

Edge Cases Handled:

  • āœ… Circular FK dependencies (detected via DependencyResolver, validated for orphans)
  • āœ… Self-referencing tables (hierarchical data - employees→managers, categories→parent)
  • āœ… Composite foreign keys (multi-column WHERE with AND logic)
  • āœ… NULL-able FK columns (NULL in any column makes entire FK NULL, not orphan)
  • āœ… Large table sampling (configurable threshold: 100k rows, uses sys.partitions stats)
  • āœ… Column length truncation (MAX(LEN()) vs schema max)
  • āœ… Identity columns (tracked but skipped for validation)
  • āœ… Computed columns (tracked but skipped for validation)
  • āœ… PII pattern whitelisting (test@example.com, 555-0100 test data)
  • āœ… PII pattern exceptions (per-table.column configuration)
  • āœ… Data type precision changes (NUMERIC_PRECISION, NUMERIC_SCALE, DATETIME_PRECISION)
  • āœ… Dropped FK constraints (INFORMATION_SCHEMA query detects missing constraints)

Configuration Options:

  • enable_row_count_check, enable_null_check, enable_fk_check (default: True)
  • enable_pii_check, enable_data_type_check, enable_column_length_check (default: True)
  • acceptable_orphan_percentage (default: 0.0%)
  • acceptable_null_delta_percentage (default: 0.0%)
  • pii_sample_size (default: 1000 rows)
  • pii_pattern_whitelist (List[str] regex patterns)
  • pii_pattern_exceptions (Dict[str, List[str]] - table.column → patterns)
  • row_count_sampling_enabled (default: True for tables > 100k rows)
  • row_count_sample_size (default: 100000)
  • fail_on_warning (default: False)

Usage Example:

# Configure validation
validation_config = ValidationConfig(
    enable_pii_check=True,
    pii_sample_size=5000,
    pii_pattern_whitelist=[r"test@example\\.com", r"555-0100"],
    pii_pattern_exceptions={
        "dbo.Customers.email": [r".*@testdomain\\.com"]
    },
    acceptable_orphan_percentage=0.1,
    row_count_sampling_enabled=True
)

# Initialize validator
validator = IntegrityValidator(conn_mgr, schema_extractor)

# Capture pre-sanitization baseline
pre_snapshot = validator.capture_pre_snapshot(
    operation_id=operation_id,
    tables=["dbo.Customers", "dbo.Orders"]
)

# ... perform sanitization ...

# Verify post-sanitization
post_snapshot = validator.capture_post_snapshot(
    operation_id=operation_id,
    tables=["dbo.Customers", "dbo.Orders"]
)

# Generate comparison report
report = validator.compare_snapshots(
    pre_snapshot,
    post_snapshot,
    config=validation_config
)

# Export report
files = report.export(format="both")  # JSON + HTML
print(f"Reports generated: {', '.join(files)}")

# Check for critical issues
if report.has_critical_issues():
    print(f"Validation FAILED: {report.critical_errors} errors")
    for error in report.validation_result.errors:
        print(f"  - {error}")
else:
    print(f"Validation PASSED: {report.overall_status}")

Performance Optimizations:

  • Large table sampling (sys.partitions for row estimates)
  • Batch FK orphan queries (EXISTS subquery pattern)
  • Top N + NEWID() for random sampling
  • Configurable PII sample size (balance accuracy vs speed)
  • Query-based validation (no full data loads)

Dependencies: Story 1.1 (Connection Manager), Story 2.1 (Schema Extraction), Story 2.2 (Dependency Resolver)


PHASE 6: Testing, Documentation & Polish (3 Stories)

Story 6.1: Unit Tests for All Modules

Status: āœ… Completed
Priority: HIGH
Estimated Effort: 3 days
Actual Effort: 3 days
Completed: 2026-03-27

User Story:
As a developer, I want comprehensive unit tests so that I can ensure code correctness and prevent regressions.

Acceptance Criteria:

  • āœ… Test coverage > 80%
  • āœ… Test all maskers with edge cases
  • āœ… Test dependency graph builder (circular FKs)
  • āœ… Test batch processing (pagination)
  • āœ… Test configuration validation
  • āœ… Mock external dependencies (database, AI API)

Technical Details:

  • Framework: pytest 7.0+
  • Location: tests/unit/, tests/conftest.py, tests/test_helpers.py
  • Mocking: unittest.mock
  • Configuration: pytest.ini with coverage settings

Implementation Summary:

  • āœ… Phase 1: Test Infrastructure (~850 LOC)

    • tests/conftest.py - Shared pytest fixtures (mock_connection, mock_cursor, mock_connection_manager, faker_instance, etc.)
    • pytest.ini - Test configuration (coverage: 80%+, markers, logging, timeout settings)
    • tests/test_helpers.py - MockCursor class, mock builders, edge case generators, SQL assertion helpers
  • āœ… Phase 2: TIER 1 Critical Module Tests (~2,330 LOC)

    • test_transaction_manager.py (~780 LOC) - 82 tests covering initialization, begin/commit/rollback, savepoints, isolation levels, timeout handling, rollback hooks, audit trail, thread safety, edge cases
    • test_integrity_validator.py (~960 LOC) - 73 tests covering ValidationConfig, ValidationPhase, TableMetrics, FKRelationshipStatus, IntegrityReport (to_dict/to_json/to_html/export), FK constraint validation, composite FK integrity, circular dependencies, self-referencing tables, row count sampling, column length preservation, NULL preservation, data type precision, PII pattern whitelist, masking effectiveness
    • test_encryption_utils.py (~590 LOC) - 78 tests covering EncryptionManager initialization, generate_key(), is_key_valid(), encrypt/decrypt, round-trip tests, NULL handling, Unicode/long strings/special characters, error handling
  • āœ… Phase 3: TIER 2 High Priority Module Tests (~800 LOC)

    • test_mapping_models.py (~700 LOC) - 65 tests covering MappingEntry (creation, validation, to_dict, NULL values, edge cases), MappingBatch (creation, validation, properties, progress percent, to_dict), MappingStats (creation, validation, duration_seconds, avg_entries_per_table/column)
    • test_error_codes.py (~100 LOC) - 9 tests covering error code constants, uniqueness, naming conventions

Test Coverage by Module:

  • TransactionManager: ~95% coverage (all methods, edge cases, concurrency)
  • IntegrityValidator: ~90% coverage (all validation methods, report generation)
  • EncryptionManager: ~95% coverage (encryption/decryption round-trips, key validation)
  • MappingModels: ~100% coverage (all dataclasses, validation, properties)
  • ErrorCodes: ~100% coverage (all constants, naming patterns)

Test Organization:

tests/
ā”œā”€ā”€ conftest.py              # Shared fixtures (~450 LOC)
ā”œā”€ā”€ test_helpers.py          # Test utilities (~400 LOC)
ā”œā”€ā”€ unit/
│   ā”œā”€ā”€ test_transaction_manager.py          (~780 LOC, 82 tests)
│   ā”œā”€ā”€ test_integrity_validator.py          (~960 LOC, 73 tests)
│   ā”œā”€ā”€ test_encryption_utils.py            (~590 LOC, 78 tests)
│   ā”œā”€ā”€ test_mapping_models.py              (~700 LOC, 65 tests)
│   ā”œā”€ā”€ test_error_codes.py                 (~100 LOC, 9 tests)
│   ā”œā”€ā”€ test_name_masker.py                  [existing]
│   ā”œā”€ā”€ test_email_masker.py                 [existing]
│   ā”œā”€ā”€ test_phone_masker.py                 [existing]
│   ā”œā”€ā”€ test_ssn_masker.py                   [existing]
│   ā”œā”€ā”€ test_generic_masker.py               [existing]
│   ā”œā”€ā”€ test_masker_factory.py               [existing]
│   ā”œā”€ā”€ test_orchestrator.py                 [existing]
│   ā”œā”€ā”€ test_desensitizer.py                 [existing]
│   └── ... [22 more existing test files]
ā”œā”€ā”€ integration/
│   └── ... [13 existing integration test files]
└── pytest.ini               # Pytest configuration (~70 lines)

Pytest Configuration:

  • Coverage threshold: --cov-fail-under=80
  • Coverage reports: HTML, XML, terminal with missing lines
  • Markers: unit, integration, slow, smoke, regression, security, edge_case
  • Logging: CLI level INFO, file level DEBUG
  • Timeout: 300 seconds (5 minutes)
  • Test discovery: test_*.py, Test* classes, test_* functions

Test Helpers & Fixtures:

  • Database Mocks: mock_cursor, mock_connection, mock_connection_manager
  • Configuration Mocks: mock_database_config, mock_sanitization_config, mock_mapping_config
  • Test Data: sample_table_data (PII samples), sample_fk_metadata (simple, composite, circular, self-referencing)
  • Edge Case Generators: unicode_test_data (10 languages), long_string_test_data (255-64KB), edge_date_test_data
  • MockCursor Class: Query tracking, result simulation, assertion helpers (assert_query_contains, assert_query_count)
  • SQL Assertion Helpers: assert_sql_contains(), assert_sql_not_contains(), assert_parameterized_query()

Edge Cases Covered:

  • TransactionManager: Nested transactions (savepoints), max depth exceeded, isolation levels, timeout, deadlocks, concurrent access, invalid savepoint names
  • IntegrityValidator: Circular FK dependencies, self-referencing tables, composite FKs, NULL-able FKs, large table sampling, column truncation, zero rows, Unicode data
  • EncryptionUtils: Wrong key decryption, corrupted ciphertext, empty strings, NULL values, Unicode strings, very long strings (1MB+), whitespace-only, repeated encryption
  • MappingModels: Invalid UUIDs, empty names, wrong hash length, NULL conflicts, negative values, completed_at before started_at, zero tables/columns

Test Statistics:

  • New Test Files: 5 files (~3,980 LOC)
  • Infrastructure Files: 3 files (~850 LOC)
  • Total New Test Code: ~4,830 LOC
  • Existing Test Files: 27 unit + 13 integration = 40 files
  • Total Test Count: 307+ new tests + 300+ existing = 600+ tests
  • Estimated Coverage: 85%+ overall (exceeds 80% target)
  • Execution Time: ~5-10 seconds for unit tests (fast, isolated)

Dependencies: All implementation stories


Story 6.2: Integration Tests with Test Database

Status: ⬜ Not Started
Priority: HIGH
Estimated Effort: 2 days

User Story:
As a developer, I want integration tests against a real SQL Server instance so that I can validate end-to-end workflows.

Acceptance Criteria:

  • āœ… Test database setup script (DDL + sample data)
  • āœ… Test complete sanitization workflow
  • āœ… Test desensitization workflow
  • āœ… Test FK integrity preservation
  • āœ… Test circular FK handling
  • āœ… Test self-referencing tables
  • āœ… Cleanup test data after each run

Technical Details:

  • Location: tests/integration/
  • Setup: scripts/setup_test_db.sql
  • Test DB: SanitizationTest

Dependencies: All implementation stories


Story 6.3: Comprehensive Documentation

Status: ⬜ Not Started
Priority: MEDIUM
Estimated Effort: 2 days

User Story:
As a user/developer, I want comprehensive documentation so that I can understand, use, and extend the system.

Acceptance Criteria:

  • āœ… README with quickstart guide
  • āœ… Installation instructions
  • āœ… Configuration guide
  • āœ… API reference documentation
  • āœ… Architecture diagrams
  • āœ… Edge case handling guide
  • āœ… Performance tuning guide
  • āœ… Security best practices

Documentation Structure:

docs/
ā”œā”€ā”€ README.md
ā”œā”€ā”€ quickstart.md
ā”œā”€ā”€ installation.md
ā”œā”€ā”€ configuration.md
ā”œā”€ā”€ architecture.md
ā”œā”€ā”€ api-reference.md
ā”œā”€ā”€ edge-cases.md
ā”œā”€ā”€ performance.md
└── security.md

Dependencies: All implementation stories


Summary Statistics

  • Total Stories: 28
  • Completed: 23 stories (82.1%)
  • Remaining: 5 stories (17.9%)
  • Total Estimated Duration: 9-11 weeks
  • Critical Priority: 11 stories (8 completed, 3 remaining)
  • High Priority: 11 stories (10 completed, 1 remaining)
  • Medium Priority: 4 stories (3 completed, 1 remaining)
  • Low Priority: 1 story (1 completed, 0 remaining)

Phase Completion Status

  • Phase 1 (Foundation): āœ… 5/5 stories complete (100%)
  • Phase 2 (Database Layer): āœ… 5/5 stories complete (100%)
  • Phase 3 (AI Integration): āœ… 3/3 stories complete (100%)
  • Phase 4 (Masking Engine): āœ… 6/6 stories complete (100%)
  • Phase 5 (Orchestration): āœ… 5/5 stories complete (100%)
  • Phase 6 (Testing & Documentation): 🟦 1/3 stories complete (33%) - IN PROGRESS

Dependencies Overview

Phase 1 (Foundation) → Phase 2 (Database Layer) → Phase 3 (AI Integration)
        āœ…                      āœ…                        āœ…
                    ↓
                 Phase 4 (Masking Engine) → Phase 5 (Orchestration) → Phase 6 (Testing)
                         āœ… (100%)                  āœ… (100%)             🟦 (33%)

Next Steps

  1. āœ… Complete Phase 1 (Foundation) - DONE
  2. āœ… Complete Phase 2 (Database Layer) - DONE
  3. āœ… Complete Phase 3 (AI Integration) - DONE
  4. āœ… Complete Phase 4 (Masking Engine) - DONE
  5. āœ… Complete Phase 5 (Orchestration) - DONE
  6. āœ… Story 6.1: Unit Tests for All Modules - DONE (3 days)
  7. šŸ”„ Story 6.2: Integration Tests with Test Database (2 days) - NEXT
  8. ⬜ Story 6.3: Comprehensive Documentation (2 days)
    • āœ… Story 4.1 (Base Masker) - DONE
    • āœ… Story 4.2 (Email Masker) - DONE
    • āœ… Story 4.3 (Phone Number Masker) - DONE
    • āœ… Story 4.4 (Name Masker) - DONE
    • āœ… Story 4.5 (SSN Masker) - DONE
    • āœ… Story 4.6 (Generic String Masker) - DONE
  9. CURRENT: Phase 5 (Orchestration)
    • āœ… Story 5.1 (Masking Strategy Factory) - DONE
    • NEXT: Story 5.2 (Sanitization Orchestrator)
  10. Add missing tests:
    • Integration tests for Story 2.4 (Batch Updater)
    • Unit tests for Story 2.5 (Transaction Manager)
    • Integration tests for Story 2.5 (Transaction Manager)
  11. Complete Phase 6 (Testing & Documentation) for production readiness

Document Version: 1.0
Last Updated: 2026-03-26
Maintained By: Development Team

Related Documents