fraiseql-confiture 0.3.7__cp311-cp311-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- confiture/__init__.py +48 -0
- confiture/_core.cpython-311-darwin.so +0 -0
- confiture/cli/__init__.py +0 -0
- confiture/cli/dry_run.py +116 -0
- confiture/cli/lint_formatter.py +193 -0
- confiture/cli/main.py +1893 -0
- confiture/config/__init__.py +0 -0
- confiture/config/environment.py +263 -0
- confiture/core/__init__.py +51 -0
- confiture/core/anonymization/__init__.py +0 -0
- confiture/core/anonymization/audit.py +485 -0
- confiture/core/anonymization/benchmarking.py +372 -0
- confiture/core/anonymization/breach_notification.py +652 -0
- confiture/core/anonymization/compliance.py +617 -0
- confiture/core/anonymization/composer.py +298 -0
- confiture/core/anonymization/data_subject_rights.py +669 -0
- confiture/core/anonymization/factory.py +319 -0
- confiture/core/anonymization/governance.py +737 -0
- confiture/core/anonymization/performance.py +1092 -0
- confiture/core/anonymization/profile.py +284 -0
- confiture/core/anonymization/registry.py +195 -0
- confiture/core/anonymization/security/kms_manager.py +547 -0
- confiture/core/anonymization/security/lineage.py +888 -0
- confiture/core/anonymization/security/token_store.py +686 -0
- confiture/core/anonymization/strategies/__init__.py +41 -0
- confiture/core/anonymization/strategies/address.py +359 -0
- confiture/core/anonymization/strategies/credit_card.py +374 -0
- confiture/core/anonymization/strategies/custom.py +161 -0
- confiture/core/anonymization/strategies/date.py +218 -0
- confiture/core/anonymization/strategies/differential_privacy.py +398 -0
- confiture/core/anonymization/strategies/email.py +141 -0
- confiture/core/anonymization/strategies/format_preserving_encryption.py +310 -0
- confiture/core/anonymization/strategies/hash.py +150 -0
- confiture/core/anonymization/strategies/ip_address.py +235 -0
- confiture/core/anonymization/strategies/masking_retention.py +252 -0
- confiture/core/anonymization/strategies/name.py +298 -0
- confiture/core/anonymization/strategies/phone.py +119 -0
- confiture/core/anonymization/strategies/preserve.py +85 -0
- confiture/core/anonymization/strategies/redact.py +101 -0
- confiture/core/anonymization/strategies/salted_hashing.py +322 -0
- confiture/core/anonymization/strategies/text_redaction.py +183 -0
- confiture/core/anonymization/strategies/tokenization.py +334 -0
- confiture/core/anonymization/strategy.py +241 -0
- confiture/core/anonymization/syncer_audit.py +357 -0
- confiture/core/blue_green.py +683 -0
- confiture/core/builder.py +500 -0
- confiture/core/checksum.py +358 -0
- confiture/core/connection.py +184 -0
- confiture/core/differ.py +522 -0
- confiture/core/drift.py +564 -0
- confiture/core/dry_run.py +182 -0
- confiture/core/health.py +313 -0
- confiture/core/hooks/__init__.py +87 -0
- confiture/core/hooks/base.py +232 -0
- confiture/core/hooks/context.py +146 -0
- confiture/core/hooks/execution_strategies.py +57 -0
- confiture/core/hooks/observability.py +220 -0
- confiture/core/hooks/phases.py +53 -0
- confiture/core/hooks/registry.py +295 -0
- confiture/core/large_tables.py +775 -0
- confiture/core/linting/__init__.py +70 -0
- confiture/core/linting/composer.py +192 -0
- confiture/core/linting/libraries/__init__.py +17 -0
- confiture/core/linting/libraries/gdpr.py +168 -0
- confiture/core/linting/libraries/general.py +184 -0
- confiture/core/linting/libraries/hipaa.py +144 -0
- confiture/core/linting/libraries/pci_dss.py +104 -0
- confiture/core/linting/libraries/sox.py +120 -0
- confiture/core/linting/schema_linter.py +491 -0
- confiture/core/linting/versioning.py +151 -0
- confiture/core/locking.py +389 -0
- confiture/core/migration_generator.py +298 -0
- confiture/core/migrator.py +882 -0
- confiture/core/observability/__init__.py +44 -0
- confiture/core/observability/audit.py +323 -0
- confiture/core/observability/logging.py +187 -0
- confiture/core/observability/metrics.py +174 -0
- confiture/core/observability/tracing.py +192 -0
- confiture/core/pg_version.py +418 -0
- confiture/core/pool.py +406 -0
- confiture/core/risk/__init__.py +39 -0
- confiture/core/risk/predictor.py +188 -0
- confiture/core/risk/scoring.py +248 -0
- confiture/core/rollback_generator.py +388 -0
- confiture/core/schema_analyzer.py +769 -0
- confiture/core/schema_to_schema.py +590 -0
- confiture/core/security/__init__.py +32 -0
- confiture/core/security/logging.py +201 -0
- confiture/core/security/validation.py +416 -0
- confiture/core/signals.py +371 -0
- confiture/core/syncer.py +540 -0
- confiture/exceptions.py +192 -0
- confiture/integrations/__init__.py +0 -0
- confiture/models/__init__.py +24 -0
- confiture/models/lint.py +193 -0
- confiture/models/migration.py +265 -0
- confiture/models/schema.py +203 -0
- confiture/models/sql_file_migration.py +225 -0
- confiture/scenarios/__init__.py +36 -0
- confiture/scenarios/compliance.py +586 -0
- confiture/scenarios/ecommerce.py +199 -0
- confiture/scenarios/financial.py +253 -0
- confiture/scenarios/healthcare.py +315 -0
- confiture/scenarios/multi_tenant.py +340 -0
- confiture/scenarios/saas.py +295 -0
- confiture/testing/FRAMEWORK_API.md +722 -0
- confiture/testing/__init__.py +100 -0
- confiture/testing/fixtures/__init__.py +11 -0
- confiture/testing/fixtures/data_validator.py +229 -0
- confiture/testing/fixtures/migration_runner.py +167 -0
- confiture/testing/fixtures/schema_snapshotter.py +352 -0
- confiture/testing/frameworks/__init__.py +10 -0
- confiture/testing/frameworks/mutation.py +587 -0
- confiture/testing/frameworks/performance.py +479 -0
- confiture/testing/loader.py +225 -0
- confiture/testing/pytest/__init__.py +38 -0
- confiture/testing/pytest_plugin.py +190 -0
- confiture/testing/sandbox.py +304 -0
- confiture/testing/utils/__init__.py +0 -0
- fraiseql_confiture-0.3.7.dist-info/METADATA +438 -0
- fraiseql_confiture-0.3.7.dist-info/RECORD +124 -0
- fraiseql_confiture-0.3.7.dist-info/WHEEL +4 -0
- fraiseql_confiture-0.3.7.dist-info/entry_points.txt +4 -0
- fraiseql_confiture-0.3.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""E-commerce customer data anonymization scenario.
|
|
2
|
+
|
|
3
|
+
Real-world use case: Anonymizing customer data for analytics while protecting PII.
|
|
4
|
+
|
|
5
|
+
Data Types:
|
|
6
|
+
- Customer names (PII)
|
|
7
|
+
- Email addresses (PII)
|
|
8
|
+
- Phone numbers (PII)
|
|
9
|
+
- Physical addresses (PII)
|
|
10
|
+
- Birth dates (sensitive)
|
|
11
|
+
- Payment methods (PCI-DSS)
|
|
12
|
+
- Order totals (safe to keep)
|
|
13
|
+
- Order dates (may need masking)
|
|
14
|
+
|
|
15
|
+
Strategy:
|
|
16
|
+
- Names: Firstname/lastname format
|
|
17
|
+
- Emails: Email redaction pattern
|
|
18
|
+
- Phone: Phone masking
|
|
19
|
+
- Addresses: Field preservation (city, state only)
|
|
20
|
+
- Dates: Month/year only
|
|
21
|
+
- Credit cards: Last 4 digits only
|
|
22
|
+
- Order totals: Preserve as-is
|
|
23
|
+
- Order dates: Preserve year/month
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from confiture.core.anonymization.factory import StrategyFactory, StrategyProfile
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ECommerceScenario:
|
|
30
|
+
"""E-commerce data anonymization scenario.
|
|
31
|
+
|
|
32
|
+
Demonstrates anonymizing customer data while preserving business analytics data.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
>>> scenario = ECommerceScenario()
|
|
36
|
+
>>> data = {
|
|
37
|
+
... "customer_id": "CUST-12345",
|
|
38
|
+
... "first_name": "John",
|
|
39
|
+
... "last_name": "Doe",
|
|
40
|
+
... "email": "john.doe@example.com",
|
|
41
|
+
... "phone": "555-123-4567",
|
|
42
|
+
... "address": "123 Main St, Anytown, CA 90210",
|
|
43
|
+
... "birth_date": "1985-06-15",
|
|
44
|
+
... "payment_method": "Visa",
|
|
45
|
+
... "card_number": "4242424242424242",
|
|
46
|
+
... "order_total": 129.99,
|
|
47
|
+
... "order_date": "2024-12-15",
|
|
48
|
+
... }
|
|
49
|
+
>>> anonymized = scenario.anonymize(data)
|
|
50
|
+
>>> # PII masked, business data preserved
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def get_profile() -> StrategyProfile:
|
|
55
|
+
"""Get E-commerce anonymization profile.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
StrategyProfile configured for e-commerce data.
|
|
59
|
+
|
|
60
|
+
Strategy Mapping:
|
|
61
|
+
- customer_id: preserve (business identifier)
|
|
62
|
+
- first_name: name masking (firstname only)
|
|
63
|
+
- last_name: name masking (lastname only)
|
|
64
|
+
- email: email redaction
|
|
65
|
+
- phone: phone masking
|
|
66
|
+
- address: address masking (city/state only)
|
|
67
|
+
- birth_date: date masking (preserve year/month)
|
|
68
|
+
- payment_method: preserve (business data)
|
|
69
|
+
- card_number: credit card masking (last 4)
|
|
70
|
+
- order_total: preserve (business data)
|
|
71
|
+
- order_date: date masking (preserve year/month)
|
|
72
|
+
"""
|
|
73
|
+
return StrategyProfile(
|
|
74
|
+
name="ecommerce",
|
|
75
|
+
seed=42, # Fixed seed for reproducibility
|
|
76
|
+
columns={
|
|
77
|
+
# Identifiers - preserve
|
|
78
|
+
"customer_id": "preserve",
|
|
79
|
+
"order_id": "preserve",
|
|
80
|
+
# PII - mask
|
|
81
|
+
"first_name": "name",
|
|
82
|
+
"last_name": "name",
|
|
83
|
+
"full_name": "name",
|
|
84
|
+
"customer_name": "name",
|
|
85
|
+
# Contact - redact
|
|
86
|
+
"email": "text_redaction",
|
|
87
|
+
"phone": "text_redaction",
|
|
88
|
+
"phone_number": "text_redaction",
|
|
89
|
+
# Address - preserve with masking
|
|
90
|
+
"address": "address",
|
|
91
|
+
"street": "address",
|
|
92
|
+
"city": "preserve", # Often kept for analytics
|
|
93
|
+
"state": "preserve",
|
|
94
|
+
"zip": "preserve",
|
|
95
|
+
"postal_code": "preserve",
|
|
96
|
+
# Sensitive dates - mask month/year
|
|
97
|
+
"birth_date": "date",
|
|
98
|
+
"dob": "date",
|
|
99
|
+
"date_of_birth": "date",
|
|
100
|
+
# Payment - PCI-DSS compliant
|
|
101
|
+
"payment_method": "preserve",
|
|
102
|
+
"payment_type": "preserve",
|
|
103
|
+
"card_type": "preserve",
|
|
104
|
+
"card_number": "credit_card",
|
|
105
|
+
# Business data - preserve
|
|
106
|
+
"order_total": "preserve",
|
|
107
|
+
"order_amount": "preserve",
|
|
108
|
+
"subtotal": "preserve",
|
|
109
|
+
"tax": "preserve",
|
|
110
|
+
"shipping": "preserve",
|
|
111
|
+
"discount": "preserve",
|
|
112
|
+
"quantity": "preserve",
|
|
113
|
+
"product_id": "preserve",
|
|
114
|
+
"sku": "preserve",
|
|
115
|
+
# Dates - preserve with masking
|
|
116
|
+
"order_date": "date",
|
|
117
|
+
"purchase_date": "date",
|
|
118
|
+
"created_at": "date",
|
|
119
|
+
"updated_at": "date",
|
|
120
|
+
"shipped_date": "date",
|
|
121
|
+
"delivered_date": "date",
|
|
122
|
+
# Location data
|
|
123
|
+
"ip_address": "ip_address",
|
|
124
|
+
"country": "preserve",
|
|
125
|
+
"region": "preserve",
|
|
126
|
+
},
|
|
127
|
+
defaults="preserve",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def create_factory(cls) -> StrategyFactory:
|
|
132
|
+
"""Create factory for e-commerce anonymization.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Configured StrategyFactory for e-commerce data.
|
|
136
|
+
"""
|
|
137
|
+
profile = cls.get_profile()
|
|
138
|
+
return StrategyFactory(profile)
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def anonymize(cls, data: dict) -> dict:
|
|
142
|
+
"""Anonymize e-commerce data.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
data: Customer/order data dictionary.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Anonymized data with PII masked and business data preserved.
|
|
149
|
+
|
|
150
|
+
Example:
|
|
151
|
+
>>> data = {
|
|
152
|
+
... "customer_id": "CUST-12345",
|
|
153
|
+
... "first_name": "John",
|
|
154
|
+
... "email": "john@example.com",
|
|
155
|
+
... "order_total": 129.99,
|
|
156
|
+
... }
|
|
157
|
+
>>> result = ECommerceScenario.anonymize(data)
|
|
158
|
+
>>> result["customer_id"] # Preserved
|
|
159
|
+
'CUST-12345'
|
|
160
|
+
>>> result["first_name"] # Anonymized
|
|
161
|
+
'Michael'
|
|
162
|
+
>>> result["email"] # Redacted
|
|
163
|
+
'[EMAIL]'
|
|
164
|
+
>>> result["order_total"] # Preserved
|
|
165
|
+
129.99
|
|
166
|
+
"""
|
|
167
|
+
factory = cls.create_factory()
|
|
168
|
+
return factory.anonymize(data)
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def anonymize_batch(cls, data_list: list[dict]) -> list[dict]:
|
|
172
|
+
"""Anonymize batch of e-commerce data.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
data_list: List of customer/order data dictionaries.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
List of anonymized data records.
|
|
179
|
+
|
|
180
|
+
Example:
|
|
181
|
+
>>> data = [
|
|
182
|
+
... {"customer_id": "CUST-1", "first_name": "John", ...},
|
|
183
|
+
... {"customer_id": "CUST-2", "first_name": "Jane", ...},
|
|
184
|
+
... ]
|
|
185
|
+
>>> results = ECommerceScenario.anonymize_batch(data)
|
|
186
|
+
"""
|
|
187
|
+
factory = cls.create_factory()
|
|
188
|
+
return [factory.anonymize(record) for record in data_list]
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def get_strategy_info(cls) -> dict:
|
|
192
|
+
"""Get information about strategies used.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Dictionary mapping column names to strategy names.
|
|
196
|
+
"""
|
|
197
|
+
profile = cls.get_profile()
|
|
198
|
+
factory = StrategyFactory(profile)
|
|
199
|
+
return factory.list_column_strategies()
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Financial services PII and sensitive data anonymization scenario.
|
|
2
|
+
|
|
3
|
+
Real-world use case: Anonymizing loan applications, credit data, and financial records.
|
|
4
|
+
|
|
5
|
+
Data Types:
|
|
6
|
+
- Applicant names (PII)
|
|
7
|
+
- Social security numbers (PII - highly sensitive)
|
|
8
|
+
- Email addresses (PII)
|
|
9
|
+
- Phone numbers (PII)
|
|
10
|
+
- Physical addresses (PII)
|
|
11
|
+
- Employment information (sensitive)
|
|
12
|
+
- Income data (sensitive)
|
|
13
|
+
- Credit scores (sensitive)
|
|
14
|
+
- Bank account information (PCI-DSS)
|
|
15
|
+
- Loan amounts (preserve for analysis)
|
|
16
|
+
- Interest rates (preserve for analysis)
|
|
17
|
+
- Credit limit (preserve for analysis)
|
|
18
|
+
- Dates (application, decision, disbursement)
|
|
19
|
+
- Employment dates (sensitive)
|
|
20
|
+
|
|
21
|
+
Strategy:
|
|
22
|
+
- Names: Complete masking
|
|
23
|
+
- SSN: Pattern redaction (###-##-XXXX)
|
|
24
|
+
- Email: Email redaction
|
|
25
|
+
- Phone: Phone masking
|
|
26
|
+
- Addresses: Field preservation (state/zip)
|
|
27
|
+
- Employment: Name masking + dates
|
|
28
|
+
- Income: Preserve (business data)
|
|
29
|
+
- Credit scores: Preserve (business data)
|
|
30
|
+
- Bank accounts: Hash replacement
|
|
31
|
+
- Loan amounts: Preserve (business data)
|
|
32
|
+
- Dates: Preserve year/month
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
from confiture.core.anonymization.factory import StrategyFactory, StrategyProfile
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FinancialScenario:
|
|
39
|
+
"""Financial services data anonymization scenario.
|
|
40
|
+
|
|
41
|
+
Demonstrates anonymizing loan applications and credit data while preserving
|
|
42
|
+
financial analytics data.
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
>>> scenario = FinancialScenario()
|
|
46
|
+
>>> data = {
|
|
47
|
+
... "application_id": "APP-2024-001",
|
|
48
|
+
... "applicant_name": "John Smith",
|
|
49
|
+
... "ssn": "123-45-6789",
|
|
50
|
+
... "text_redaction": "john.smith@example.com",
|
|
51
|
+
... "text_redaction": "555-123-4567",
|
|
52
|
+
... "address": "123 Main St, Anytown, CA 90210",
|
|
53
|
+
... "employment_name": "Acme Corp",
|
|
54
|
+
... "employment_address": "456 Corporate Blvd",
|
|
55
|
+
... "employment_start": "2015-06-01",
|
|
56
|
+
... "employment_end": "2024-01-15",
|
|
57
|
+
... "annual_income": 75000,
|
|
58
|
+
... "credit_score": 750,
|
|
59
|
+
... "bank_account": "4532194857632145",
|
|
60
|
+
... "loan_amount": 250000,
|
|
61
|
+
... "interest_rate": 4.5,
|
|
62
|
+
... "loan_term": 30,
|
|
63
|
+
... "application_date": "2024-11-01",
|
|
64
|
+
... "decision_date": "2024-11-15",
|
|
65
|
+
... }
|
|
66
|
+
>>> anonymized = scenario.anonymize(data)
|
|
67
|
+
>>> # PII masked, financial metrics preserved
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def get_profile() -> StrategyProfile:
|
|
72
|
+
"""Get financial data anonymization profile.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
StrategyProfile configured for financial data anonymization.
|
|
76
|
+
|
|
77
|
+
Strategy Mapping:
|
|
78
|
+
- application_id: preserve (business identifier)
|
|
79
|
+
- applicant_name: name masking
|
|
80
|
+
- ssn: SSN pattern redaction
|
|
81
|
+
- email: email redaction
|
|
82
|
+
- phone: phone masking
|
|
83
|
+
- address: address masking (preserve state/zip)
|
|
84
|
+
- employment_name: name masking
|
|
85
|
+
- employment_address: address masking
|
|
86
|
+
- employment dates: date masking (preserve year/month)
|
|
87
|
+
- income: preserve (business data)
|
|
88
|
+
- credit_score: preserve (business data)
|
|
89
|
+
- bank_account: custom hash
|
|
90
|
+
- loan_amount: preserve (business data)
|
|
91
|
+
- interest_rate: preserve (business data)
|
|
92
|
+
- application_date: date masking
|
|
93
|
+
"""
|
|
94
|
+
return StrategyProfile(
|
|
95
|
+
name="financial_services",
|
|
96
|
+
seed=42, # Fixed seed for reproducibility
|
|
97
|
+
columns={
|
|
98
|
+
# Application identifiers - preserve
|
|
99
|
+
"application_id": "preserve",
|
|
100
|
+
"loan_id": "preserve",
|
|
101
|
+
"account_id": "preserve",
|
|
102
|
+
"reference_number": "preserve",
|
|
103
|
+
# Applicant PII - mask
|
|
104
|
+
"applicant_name": "name",
|
|
105
|
+
"first_name": "name",
|
|
106
|
+
"last_name": "name",
|
|
107
|
+
"full_name": "name",
|
|
108
|
+
"co_applicant_name": "name",
|
|
109
|
+
# Sensitive identifiers - redact
|
|
110
|
+
"ssn": "text_redaction",
|
|
111
|
+
"social_security_number": "text_redaction",
|
|
112
|
+
"tax_id": "text_redaction",
|
|
113
|
+
"ein": "text_redaction",
|
|
114
|
+
# Contact - redact
|
|
115
|
+
"email": "text_redaction",
|
|
116
|
+
"phone": "text_redaction",
|
|
117
|
+
"phone_number": "text_redaction",
|
|
118
|
+
"cell_phone": "text_redaction",
|
|
119
|
+
"work_phone": "text_redaction",
|
|
120
|
+
# Address - preserve with masking
|
|
121
|
+
"address": "address",
|
|
122
|
+
"street_address": "address",
|
|
123
|
+
"city": "preserve",
|
|
124
|
+
"state": "preserve",
|
|
125
|
+
"zip": "preserve",
|
|
126
|
+
"postal_code": "preserve",
|
|
127
|
+
"country": "preserve",
|
|
128
|
+
# Employment - mask employer name but preserve dates
|
|
129
|
+
"employer_name": "name",
|
|
130
|
+
"employment_name": "name",
|
|
131
|
+
"job_title": "preserve",
|
|
132
|
+
"position": "preserve",
|
|
133
|
+
"employment_address": "address",
|
|
134
|
+
"employment_start_date": "date",
|
|
135
|
+
"employment_end_date": "date",
|
|
136
|
+
"employment_duration": "preserve",
|
|
137
|
+
"years_employed": "preserve",
|
|
138
|
+
# Financial metrics - preserve
|
|
139
|
+
"annual_income": "preserve",
|
|
140
|
+
"income": "preserve",
|
|
141
|
+
"gross_income": "preserve",
|
|
142
|
+
"net_income": "preserve",
|
|
143
|
+
"monthly_income": "preserve",
|
|
144
|
+
"other_income": "preserve",
|
|
145
|
+
"total_assets": "preserve",
|
|
146
|
+
"total_liabilities": "preserve",
|
|
147
|
+
# Credit data - preserve
|
|
148
|
+
"credit_score": "preserve",
|
|
149
|
+
"fico_score": "preserve",
|
|
150
|
+
"credit_limit": "preserve",
|
|
151
|
+
"available_credit": "preserve",
|
|
152
|
+
"outstanding_balance": "preserve",
|
|
153
|
+
"debt_to_income": "preserve",
|
|
154
|
+
"payment_history": "preserve",
|
|
155
|
+
# Bank/Payment - hash accounts
|
|
156
|
+
"bank_account": "custom",
|
|
157
|
+
"bank_account_number": "custom",
|
|
158
|
+
"routing_number": "custom",
|
|
159
|
+
"card_number": "credit_card",
|
|
160
|
+
"account_number": "custom",
|
|
161
|
+
# Loan details - preserve
|
|
162
|
+
"loan_amount": "preserve",
|
|
163
|
+
"principal": "preserve",
|
|
164
|
+
"interest_rate": "preserve",
|
|
165
|
+
"apr": "preserve",
|
|
166
|
+
"loan_term": "preserve",
|
|
167
|
+
"monthly_payment": "preserve",
|
|
168
|
+
"loan_type": "preserve",
|
|
169
|
+
"loan_purpose": "preserve",
|
|
170
|
+
"collateral": "preserve",
|
|
171
|
+
# Dates - mask to year/month
|
|
172
|
+
"application_date": "date",
|
|
173
|
+
"decision_date": "date",
|
|
174
|
+
"approval_date": "date",
|
|
175
|
+
"disbursement_date": "date",
|
|
176
|
+
"closing_date": "date",
|
|
177
|
+
"maturity_date": "date",
|
|
178
|
+
"payment_due_date": "preserve",
|
|
179
|
+
# Document references
|
|
180
|
+
"document_id": "preserve",
|
|
181
|
+
"document_type": "preserve",
|
|
182
|
+
"verification_status": "preserve",
|
|
183
|
+
# IP/technical - mask
|
|
184
|
+
"ip_address": "ip_address",
|
|
185
|
+
"device_id": "preserve",
|
|
186
|
+
},
|
|
187
|
+
defaults="preserve",
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def create_factory(cls) -> StrategyFactory:
|
|
192
|
+
"""Create factory for financial data anonymization.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Configured StrategyFactory for financial services.
|
|
196
|
+
"""
|
|
197
|
+
profile = cls.get_profile()
|
|
198
|
+
return StrategyFactory(profile)
|
|
199
|
+
|
|
200
|
+
@classmethod
|
|
201
|
+
def anonymize(cls, data: dict) -> dict:
|
|
202
|
+
"""Anonymize financial services data.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
data: Loan application or account data dictionary.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Anonymized data with PII masked and financial metrics preserved.
|
|
209
|
+
|
|
210
|
+
Example:
|
|
211
|
+
>>> data = {
|
|
212
|
+
... "application_id": "APP-2024-001",
|
|
213
|
+
... "applicant_name": "John Smith",
|
|
214
|
+
... "ssn": "123-45-6789",
|
|
215
|
+
... "annual_income": 75000,
|
|
216
|
+
... "credit_score": 750,
|
|
217
|
+
... }
|
|
218
|
+
>>> result = FinancialScenario.anonymize(data)
|
|
219
|
+
>>> result["application_id"] # Preserved
|
|
220
|
+
'APP-2024-001'
|
|
221
|
+
>>> result["applicant_name"] # Anonymized
|
|
222
|
+
'Michael Johnson'
|
|
223
|
+
>>> result["ssn"] # Redacted
|
|
224
|
+
'[REDACTED]'
|
|
225
|
+
>>> result["annual_income"] # Preserved
|
|
226
|
+
75000
|
|
227
|
+
"""
|
|
228
|
+
factory = cls.create_factory()
|
|
229
|
+
return factory.anonymize(data)
|
|
230
|
+
|
|
231
|
+
@classmethod
|
|
232
|
+
def anonymize_batch(cls, data_list: list[dict]) -> list[dict]:
|
|
233
|
+
"""Anonymize batch of financial records.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
data_list: List of loan/account records.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
List of anonymized financial records.
|
|
240
|
+
"""
|
|
241
|
+
factory = cls.create_factory()
|
|
242
|
+
return [factory.anonymize(record) for record in data_list]
|
|
243
|
+
|
|
244
|
+
@classmethod
|
|
245
|
+
def get_strategy_info(cls) -> dict:
|
|
246
|
+
"""Get information about strategies used.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Dictionary mapping column names to strategy names.
|
|
250
|
+
"""
|
|
251
|
+
profile = cls.get_profile()
|
|
252
|
+
factory = StrategyFactory(profile)
|
|
253
|
+
return factory.list_column_strategies()
|