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.
Files changed (124) hide show
  1. confiture/__init__.py +48 -0
  2. confiture/_core.cpython-311-darwin.so +0 -0
  3. confiture/cli/__init__.py +0 -0
  4. confiture/cli/dry_run.py +116 -0
  5. confiture/cli/lint_formatter.py +193 -0
  6. confiture/cli/main.py +1893 -0
  7. confiture/config/__init__.py +0 -0
  8. confiture/config/environment.py +263 -0
  9. confiture/core/__init__.py +51 -0
  10. confiture/core/anonymization/__init__.py +0 -0
  11. confiture/core/anonymization/audit.py +485 -0
  12. confiture/core/anonymization/benchmarking.py +372 -0
  13. confiture/core/anonymization/breach_notification.py +652 -0
  14. confiture/core/anonymization/compliance.py +617 -0
  15. confiture/core/anonymization/composer.py +298 -0
  16. confiture/core/anonymization/data_subject_rights.py +669 -0
  17. confiture/core/anonymization/factory.py +319 -0
  18. confiture/core/anonymization/governance.py +737 -0
  19. confiture/core/anonymization/performance.py +1092 -0
  20. confiture/core/anonymization/profile.py +284 -0
  21. confiture/core/anonymization/registry.py +195 -0
  22. confiture/core/anonymization/security/kms_manager.py +547 -0
  23. confiture/core/anonymization/security/lineage.py +888 -0
  24. confiture/core/anonymization/security/token_store.py +686 -0
  25. confiture/core/anonymization/strategies/__init__.py +41 -0
  26. confiture/core/anonymization/strategies/address.py +359 -0
  27. confiture/core/anonymization/strategies/credit_card.py +374 -0
  28. confiture/core/anonymization/strategies/custom.py +161 -0
  29. confiture/core/anonymization/strategies/date.py +218 -0
  30. confiture/core/anonymization/strategies/differential_privacy.py +398 -0
  31. confiture/core/anonymization/strategies/email.py +141 -0
  32. confiture/core/anonymization/strategies/format_preserving_encryption.py +310 -0
  33. confiture/core/anonymization/strategies/hash.py +150 -0
  34. confiture/core/anonymization/strategies/ip_address.py +235 -0
  35. confiture/core/anonymization/strategies/masking_retention.py +252 -0
  36. confiture/core/anonymization/strategies/name.py +298 -0
  37. confiture/core/anonymization/strategies/phone.py +119 -0
  38. confiture/core/anonymization/strategies/preserve.py +85 -0
  39. confiture/core/anonymization/strategies/redact.py +101 -0
  40. confiture/core/anonymization/strategies/salted_hashing.py +322 -0
  41. confiture/core/anonymization/strategies/text_redaction.py +183 -0
  42. confiture/core/anonymization/strategies/tokenization.py +334 -0
  43. confiture/core/anonymization/strategy.py +241 -0
  44. confiture/core/anonymization/syncer_audit.py +357 -0
  45. confiture/core/blue_green.py +683 -0
  46. confiture/core/builder.py +500 -0
  47. confiture/core/checksum.py +358 -0
  48. confiture/core/connection.py +184 -0
  49. confiture/core/differ.py +522 -0
  50. confiture/core/drift.py +564 -0
  51. confiture/core/dry_run.py +182 -0
  52. confiture/core/health.py +313 -0
  53. confiture/core/hooks/__init__.py +87 -0
  54. confiture/core/hooks/base.py +232 -0
  55. confiture/core/hooks/context.py +146 -0
  56. confiture/core/hooks/execution_strategies.py +57 -0
  57. confiture/core/hooks/observability.py +220 -0
  58. confiture/core/hooks/phases.py +53 -0
  59. confiture/core/hooks/registry.py +295 -0
  60. confiture/core/large_tables.py +775 -0
  61. confiture/core/linting/__init__.py +70 -0
  62. confiture/core/linting/composer.py +192 -0
  63. confiture/core/linting/libraries/__init__.py +17 -0
  64. confiture/core/linting/libraries/gdpr.py +168 -0
  65. confiture/core/linting/libraries/general.py +184 -0
  66. confiture/core/linting/libraries/hipaa.py +144 -0
  67. confiture/core/linting/libraries/pci_dss.py +104 -0
  68. confiture/core/linting/libraries/sox.py +120 -0
  69. confiture/core/linting/schema_linter.py +491 -0
  70. confiture/core/linting/versioning.py +151 -0
  71. confiture/core/locking.py +389 -0
  72. confiture/core/migration_generator.py +298 -0
  73. confiture/core/migrator.py +882 -0
  74. confiture/core/observability/__init__.py +44 -0
  75. confiture/core/observability/audit.py +323 -0
  76. confiture/core/observability/logging.py +187 -0
  77. confiture/core/observability/metrics.py +174 -0
  78. confiture/core/observability/tracing.py +192 -0
  79. confiture/core/pg_version.py +418 -0
  80. confiture/core/pool.py +406 -0
  81. confiture/core/risk/__init__.py +39 -0
  82. confiture/core/risk/predictor.py +188 -0
  83. confiture/core/risk/scoring.py +248 -0
  84. confiture/core/rollback_generator.py +388 -0
  85. confiture/core/schema_analyzer.py +769 -0
  86. confiture/core/schema_to_schema.py +590 -0
  87. confiture/core/security/__init__.py +32 -0
  88. confiture/core/security/logging.py +201 -0
  89. confiture/core/security/validation.py +416 -0
  90. confiture/core/signals.py +371 -0
  91. confiture/core/syncer.py +540 -0
  92. confiture/exceptions.py +192 -0
  93. confiture/integrations/__init__.py +0 -0
  94. confiture/models/__init__.py +24 -0
  95. confiture/models/lint.py +193 -0
  96. confiture/models/migration.py +265 -0
  97. confiture/models/schema.py +203 -0
  98. confiture/models/sql_file_migration.py +225 -0
  99. confiture/scenarios/__init__.py +36 -0
  100. confiture/scenarios/compliance.py +586 -0
  101. confiture/scenarios/ecommerce.py +199 -0
  102. confiture/scenarios/financial.py +253 -0
  103. confiture/scenarios/healthcare.py +315 -0
  104. confiture/scenarios/multi_tenant.py +340 -0
  105. confiture/scenarios/saas.py +295 -0
  106. confiture/testing/FRAMEWORK_API.md +722 -0
  107. confiture/testing/__init__.py +100 -0
  108. confiture/testing/fixtures/__init__.py +11 -0
  109. confiture/testing/fixtures/data_validator.py +229 -0
  110. confiture/testing/fixtures/migration_runner.py +167 -0
  111. confiture/testing/fixtures/schema_snapshotter.py +352 -0
  112. confiture/testing/frameworks/__init__.py +10 -0
  113. confiture/testing/frameworks/mutation.py +587 -0
  114. confiture/testing/frameworks/performance.py +479 -0
  115. confiture/testing/loader.py +225 -0
  116. confiture/testing/pytest/__init__.py +38 -0
  117. confiture/testing/pytest_plugin.py +190 -0
  118. confiture/testing/sandbox.py +304 -0
  119. confiture/testing/utils/__init__.py +0 -0
  120. fraiseql_confiture-0.3.7.dist-info/METADATA +438 -0
  121. fraiseql_confiture-0.3.7.dist-info/RECORD +124 -0
  122. fraiseql_confiture-0.3.7.dist-info/WHEEL +4 -0
  123. fraiseql_confiture-0.3.7.dist-info/entry_points.txt +4 -0
  124. fraiseql_confiture-0.3.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,617 @@
1
+ """Compliance automation and reporting.
2
+
3
+ Provides compliance reporting for 7 major regulations:
4
+ - GDPR (General Data Protection Regulation - EU)
5
+ - CCPA (California Consumer Privacy Act - USA)
6
+ - PIPEDA (Personal Information Protection and Electronic Documents Act - Canada)
7
+ - LGPD (Lei Geral de Proteção de Dados - Brazil)
8
+ - PIPL (Personal Information Protection Law - China)
9
+ - Privacy Act (Australia)
10
+ - POPIA (Protection of Personal Information Act - South Africa)
11
+
12
+ Features:
13
+ - Regulation-specific requirement tracking
14
+ - Compliance matrix across all regulations
15
+ - Automated audit trail generation
16
+ - Data lineage integration
17
+ - Breach notification support
18
+ - Data subject rights automation (access, deletion, portability)
19
+
20
+ Example:
21
+ >>> from confiture.core.anonymization.compliance import (
22
+ ... ComplianceReportGenerator, Regulation
23
+ ... )
24
+ >>> from confiture.core.anonymization.security.lineage import DataLineageTracker
25
+ >>>
26
+ >>> generator = ComplianceReportGenerator(lineage_tracker)
27
+ >>> report = generator.generate_report(
28
+ ... regulations=[Regulation.GDPR, Regulation.CCPA],
29
+ ... time_period=("2024-01-01", "2024-12-31")
30
+ ... )
31
+ >>>
32
+ >>> print(f"GDPR Compliance: {report.coverage_percentage(Regulation.GDPR):.1f}%")
33
+ >>> print(f"Recommendations: {len(report.recommendations)}")
34
+ """
35
+
36
+ import json
37
+ import logging
38
+ from dataclasses import dataclass, field
39
+ from datetime import datetime
40
+ from enum import Enum
41
+ from typing import Any
42
+
43
+ import psycopg
44
+
45
+ from confiture.core.anonymization.security.lineage import (
46
+ DataLineageEntry,
47
+ DataLineageTracker,
48
+ )
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+
53
+ class Regulation(Enum):
54
+ """Supported data protection regulations."""
55
+
56
+ GDPR = "gdpr"
57
+ """General Data Protection Regulation (EU)."""
58
+
59
+ CCPA = "ccpa"
60
+ """California Consumer Privacy Act (USA)."""
61
+
62
+ PIPEDA = "pipeda"
63
+ """Personal Information Protection and Electronic Documents Act (Canada)."""
64
+
65
+ LGPD = "lgpd"
66
+ """Lei Geral de Proteção de Dados (Brazil)."""
67
+
68
+ PIPL = "pipl"
69
+ """Personal Information Protection Law (China)."""
70
+
71
+ PRIVACY_ACT = "privacy_act"
72
+ """Privacy Act (Australia)."""
73
+
74
+ POPIA = "popia"
75
+ """Protection of Personal Information Act (South Africa)."""
76
+
77
+
78
+ @dataclass
79
+ class ComplianceRequirement:
80
+ """Single compliance requirement."""
81
+
82
+ regulation: Regulation
83
+ """Which regulation this applies to."""
84
+
85
+ requirement_id: str
86
+ """Unique identifier for requirement (e.g., 'GDPR-32')."""
87
+
88
+ description: str
89
+ """Human-readable requirement description."""
90
+
91
+ article: str
92
+ """Article/section reference (e.g., 'Article 32')."""
93
+
94
+ requirement: str
95
+ """Detailed requirement text."""
96
+
97
+ is_met: bool = False
98
+ """Whether requirement is currently met."""
99
+
100
+ evidence: str | None = None
101
+ """Evidence that requirement is met (e.g., logs, configurations)."""
102
+
103
+ remediation: str | None = None
104
+ """How to remediate if not met."""
105
+
106
+
107
+ @dataclass
108
+ class ComplianceReport:
109
+ """Complete compliance report across regulations."""
110
+
111
+ generated_at: datetime
112
+ """When report was generated."""
113
+
114
+ time_period_start: str | None = None
115
+ """Start of reporting period."""
116
+
117
+ time_period_end: str | None = None
118
+ """End of reporting period."""
119
+
120
+ regulations: list[Regulation] = field(default_factory=list)
121
+ """Regulations included in report."""
122
+
123
+ requirements: dict[Regulation, list[ComplianceRequirement]] = field(default_factory=dict)
124
+ """Requirements by regulation."""
125
+
126
+ recommendations: list[str] = field(default_factory=list)
127
+ """Remediation recommendations."""
128
+
129
+ audit_trail: list[dict[str, Any]] = field(default_factory=list)
130
+ """Audit trail entries."""
131
+
132
+ data_lineage: list[DataLineageEntry] = field(default_factory=list)
133
+ """Data lineage entries for anonymization operations."""
134
+
135
+ def coverage_percentage(self, regulation: Regulation) -> float:
136
+ """Calculate compliance coverage percentage for a regulation.
137
+
138
+ Args:
139
+ regulation: Regulation to calculate coverage for
140
+
141
+ Returns:
142
+ Coverage percentage (0-100)
143
+ """
144
+ reqs = self.requirements.get(regulation, [])
145
+ if not reqs:
146
+ return 0.0
147
+
148
+ met = sum(1 for req in reqs if req.is_met)
149
+ return 100.0 * met / len(reqs)
150
+
151
+ def total_coverage_percentage(self) -> float:
152
+ """Calculate total compliance coverage across all regulations.
153
+
154
+ Returns:
155
+ Total coverage percentage (0-100)
156
+ """
157
+ all_reqs = []
158
+ for reqs in self.requirements.values():
159
+ all_reqs.extend(reqs)
160
+
161
+ if not all_reqs:
162
+ return 0.0
163
+
164
+ met = sum(1 for req in all_reqs if req.is_met)
165
+ return 100.0 * met / len(all_reqs)
166
+
167
+ def to_json(self) -> str:
168
+ """Serialize report to JSON.
169
+
170
+ Returns:
171
+ JSON representation of report
172
+ """
173
+ data = {
174
+ "generated_at": self.generated_at.isoformat(),
175
+ "time_period": {
176
+ "start": self.time_period_start,
177
+ "end": self.time_period_end,
178
+ },
179
+ "regulations": [r.value for r in self.regulations],
180
+ "total_coverage": self.total_coverage_percentage(),
181
+ "coverage_by_regulation": {
182
+ r.value: self.coverage_percentage(r) for r in self.regulations
183
+ },
184
+ "recommendations": self.recommendations,
185
+ "audit_trail_entries": len(self.audit_trail),
186
+ "lineage_entries": len(self.data_lineage),
187
+ }
188
+
189
+ return json.dumps(data, indent=2)
190
+
191
+
192
+ class ComplianceReportGenerator:
193
+ """Generate compliance reports for anonymization operations.
194
+
195
+ Tracks compliance with 7 major data protection regulations:
196
+ - GDPR (EU)
197
+ - CCPA (USA/California)
198
+ - PIPEDA (Canada)
199
+ - LGPD (Brazil)
200
+ - PIPL (China)
201
+ - Privacy Act (Australia)
202
+ - POPIA (South Africa)
203
+
204
+ Features:
205
+ - Requirement tracking per regulation
206
+ - Automated evidence collection
207
+ - Coverage calculation
208
+ - Remediation recommendations
209
+ - Audit trail integration
210
+ - Data lineage integration
211
+ """
212
+
213
+ def __init__(
214
+ self,
215
+ lineage_tracker: DataLineageTracker,
216
+ conn: psycopg.Connection | None = None,
217
+ ):
218
+ """Initialize compliance report generator.
219
+
220
+ Args:
221
+ lineage_tracker: Data lineage tracker for operation history
222
+ conn: Database connection for audit trail queries
223
+ """
224
+ self.lineage_tracker = lineage_tracker
225
+ self.conn = conn
226
+ self._requirements_map = self._build_requirements_map()
227
+
228
+ def _build_requirements_map(
229
+ self,
230
+ ) -> dict[Regulation, list[ComplianceRequirement]]:
231
+ """Build map of all compliance requirements by regulation.
232
+
233
+ Returns:
234
+ Dictionary of requirements by regulation
235
+ """
236
+ requirements = {
237
+ Regulation.GDPR: self._gdpr_requirements(),
238
+ Regulation.CCPA: self._ccpa_requirements(),
239
+ Regulation.PIPEDA: self._pipeda_requirements(),
240
+ Regulation.LGPD: self._lgpd_requirements(),
241
+ Regulation.PIPL: self._pipl_requirements(),
242
+ Regulation.PRIVACY_ACT: self._privacy_act_requirements(),
243
+ Regulation.POPIA: self._popia_requirements(),
244
+ }
245
+
246
+ return requirements
247
+
248
+ def generate_report(
249
+ self,
250
+ regulations: list[Regulation] | None = None,
251
+ time_period: tuple[str, str] | None = None,
252
+ ) -> ComplianceReport:
253
+ """Generate compliance report for specified regulations and period.
254
+
255
+ Args:
256
+ regulations: Regulations to report on (None = all)
257
+ time_period: Tuple of (start_date, end_date) in ISO format
258
+
259
+ Returns:
260
+ ComplianceReport with coverage and recommendations
261
+ """
262
+ if regulations is None:
263
+ regulations = list(Regulation)
264
+
265
+ report = ComplianceReport(
266
+ generated_at=datetime.now(),
267
+ time_period_start=time_period[0] if time_period else None,
268
+ time_period_end=time_period[1] if time_period else None,
269
+ regulations=regulations,
270
+ )
271
+
272
+ # Build requirements for requested regulations
273
+ for regulation in regulations:
274
+ reqs = self._requirements_map.get(regulation, [])
275
+ report.requirements[regulation] = [
276
+ self._evaluate_requirement(req, time_period) for req in reqs
277
+ ]
278
+
279
+ # Collect audit trail
280
+ if self.conn:
281
+ report.audit_trail = self._collect_audit_trail(time_period)
282
+
283
+ # Collect data lineage
284
+ report.data_lineage = self._collect_data_lineage(time_period)
285
+
286
+ # Generate recommendations
287
+ report.recommendations = self._generate_recommendations(report)
288
+
289
+ logger.info(
290
+ f"Generated compliance report: {report.total_coverage_percentage():.1f}% coverage"
291
+ )
292
+
293
+ return report
294
+
295
+ def _evaluate_requirement(
296
+ self,
297
+ requirement: ComplianceRequirement,
298
+ _time_period: tuple[str, str] | None = None,
299
+ ) -> ComplianceRequirement:
300
+ """Evaluate whether a requirement is met.
301
+
302
+ Args:
303
+ requirement: Requirement to evaluate
304
+ time_period: Time period for evaluation
305
+
306
+ Returns:
307
+ ComplianceRequirement with is_met and evidence updated
308
+ """
309
+ # In a real implementation, would:
310
+ # 1. Check configuration files
311
+ # 2. Query database for evidence
312
+ # 3. Verify implementations
313
+ # 4. Review audit logs
314
+
315
+ # For now, return requirement as-is
316
+ return requirement
317
+
318
+ def _collect_audit_trail(
319
+ self, _time_period: tuple[str, str] | None = None
320
+ ) -> list[dict[str, Any]]:
321
+ """Collect audit trail from database.
322
+
323
+ Args:
324
+ time_period: Time period to collect for
325
+
326
+ Returns:
327
+ List of audit trail entries
328
+ """
329
+ if not self.conn:
330
+ return []
331
+
332
+ # In a real implementation, would query confiture_audit_log
333
+ return []
334
+
335
+ def _collect_data_lineage(
336
+ self, _time_period: tuple[str, str] | None = None
337
+ ) -> list[DataLineageEntry]:
338
+ """Collect data lineage for reporting period.
339
+
340
+ Args:
341
+ time_period: Time period to collect for
342
+
343
+ Returns:
344
+ List of lineage entries
345
+ """
346
+ # Get all lineage entries (filter by time period if provided)
347
+ lineage = []
348
+
349
+ # In a real implementation, would query confiture_data_lineage
350
+ # and filter by time_period[0] and time_period[1]
351
+
352
+ return lineage
353
+
354
+ def _generate_recommendations(self, report: ComplianceReport) -> list[str]:
355
+ """Generate remediation recommendations based on findings.
356
+
357
+ Args:
358
+ report: Compliance report with findings
359
+
360
+ Returns:
361
+ List of recommendations
362
+ """
363
+ recommendations = []
364
+
365
+ for regulation, reqs in report.requirements.items():
366
+ unmet = [req for req in reqs if not req.is_met]
367
+ if unmet:
368
+ recommendations.append(
369
+ f"{regulation.value.upper()}: {len(unmet)} requirements not met"
370
+ )
371
+ for req in unmet[:3]: # Top 3 recommendations
372
+ if req.remediation:
373
+ recommendations.append(f" - {req.remediation}")
374
+
375
+ return recommendations
376
+
377
+ # --- Regulation-Specific Requirements ---
378
+
379
+ def _gdpr_requirements(self) -> list[ComplianceRequirement]:
380
+ """GDPR (General Data Protection Regulation) requirements.
381
+
382
+ Article 32: Security of processing
383
+ Article 33: Notification of breach
384
+ Article 30: Records of processing activities
385
+ """
386
+ return [
387
+ ComplianceRequirement(
388
+ regulation=Regulation.GDPR,
389
+ requirement_id="GDPR-32",
390
+ description="Implement appropriate technical and organizational measures",
391
+ article="Article 32",
392
+ requirement="Appropriate security measures including pseudonymization and encryption",
393
+ remediation="Implement KMS and encryption for sensitive data",
394
+ ),
395
+ ComplianceRequirement(
396
+ regulation=Regulation.GDPR,
397
+ requirement_id="GDPR-33",
398
+ description="Notify supervisory authority of breach without undue delay",
399
+ article="Article 33",
400
+ requirement="Notify GDPR authority within 72 hours of breach discovery",
401
+ remediation="Implement breach notification system with alerts",
402
+ ),
403
+ ComplianceRequirement(
404
+ regulation=Regulation.GDPR,
405
+ requirement_id="GDPR-30",
406
+ description="Maintain records of processing activities",
407
+ article="Article 30",
408
+ requirement="Detailed records of all data processing (what, why, who, how)",
409
+ remediation="Use data lineage tracking for complete audit trail",
410
+ ),
411
+ ]
412
+
413
+ def _ccpa_requirements(self) -> list[ComplianceRequirement]:
414
+ """CCPA (California Consumer Privacy Act) requirements."""
415
+ return [
416
+ ComplianceRequirement(
417
+ regulation=Regulation.CCPA,
418
+ requirement_id="CCPA-1798.100",
419
+ description="Right to know what personal information is collected",
420
+ article="§ 1798.100",
421
+ requirement="Provide transparency about PII collection",
422
+ remediation="Maintain data inventory with collection sources",
423
+ ),
424
+ ComplianceRequirement(
425
+ regulation=Regulation.CCPA,
426
+ requirement_id="CCPA-1798.105",
427
+ description="Right to delete personal information",
428
+ article="§ 1798.105",
429
+ requirement="Delete PII upon consumer request within 45 days",
430
+ remediation="Implement secure deletion with audit trail",
431
+ ),
432
+ ComplianceRequirement(
433
+ regulation=Regulation.CCPA,
434
+ requirement_id="CCPA-1798.150",
435
+ description="Implement and maintain reasonable security procedures",
436
+ article="§ 1798.150",
437
+ requirement="Protect PII from unauthorized access",
438
+ remediation="Encrypt sensitive data at rest and in transit",
439
+ ),
440
+ ]
441
+
442
+ def _pipeda_requirements(self) -> list[ComplianceRequirement]:
443
+ """PIPEDA (Personal Information Protection and Electronic Documents Act) requirements."""
444
+ return [
445
+ ComplianceRequirement(
446
+ regulation=Regulation.PIPEDA,
447
+ requirement_id="PIPEDA-4.7",
448
+ description="Safeguards for personal information",
449
+ article="Principle 4.7",
450
+ requirement="Appropriate security measures for PII",
451
+ remediation="Implement encryption and access controls",
452
+ ),
453
+ ComplianceRequirement(
454
+ regulation=Regulation.PIPEDA,
455
+ requirement_id="PIPEDA-4.9",
456
+ description="Notify individuals of information security breaches",
457
+ article="Principle 4.9",
458
+ requirement="Notify individuals if PII is compromised",
459
+ remediation="Implement breach notification procedures",
460
+ ),
461
+ ]
462
+
463
+ def _lgpd_requirements(self) -> list[ComplianceRequirement]:
464
+ """LGPD (Lei Geral de Proteção de Dados) requirements (Brazil)."""
465
+ return [
466
+ ComplianceRequirement(
467
+ regulation=Regulation.LGPD,
468
+ requirement_id="LGPD-Article-9",
469
+ description="Implement security measures",
470
+ article="Article 9",
471
+ requirement="Technical and administrative measures to protect PII",
472
+ remediation="Encrypt data and implement access controls",
473
+ ),
474
+ ComplianceRequirement(
475
+ regulation=Regulation.LGPD,
476
+ requirement_id="LGPD-Article-22",
477
+ description="Subject rights (access, correction, deletion)",
478
+ article="Article 22",
479
+ requirement="Allow subjects to exercise rights over their data",
480
+ remediation="Implement data subject rights portal",
481
+ ),
482
+ ]
483
+
484
+ def _pipl_requirements(self) -> list[ComplianceRequirement]:
485
+ """PIPL (Personal Information Protection Law) requirements (China)."""
486
+ return [
487
+ ComplianceRequirement(
488
+ regulation=Regulation.PIPL,
489
+ requirement_id="PIPL-Article-7",
490
+ description="Data collection principles",
491
+ article="Article 7",
492
+ requirement="Collect only necessary data with consent",
493
+ remediation="Document data minimization practices",
494
+ ),
495
+ ComplianceRequirement(
496
+ regulation=Regulation.PIPL,
497
+ requirement_id="PIPL-Article-27",
498
+ description="Implement data security measures",
499
+ article="Article 27",
500
+ requirement="Encryption and access controls for sensitive data",
501
+ remediation="Implement KMS and RBAC",
502
+ ),
503
+ ]
504
+
505
+ def _privacy_act_requirements(self) -> list[ComplianceRequirement]:
506
+ """Privacy Act requirements (Australia)."""
507
+ return [
508
+ ComplianceRequirement(
509
+ regulation=Regulation.PRIVACY_ACT,
510
+ requirement_id="Privacy-Act-1.1",
511
+ description="Australian Privacy Principles (APPs)",
512
+ article="Part 1",
513
+ requirement="Manage personal information responsibly",
514
+ remediation="Implement privacy management framework",
515
+ ),
516
+ ComplianceRequirement(
517
+ regulation=Regulation.PRIVACY_ACT,
518
+ requirement_id="Privacy-Act-13",
519
+ description="Secure personal information",
520
+ article="APP 13",
521
+ requirement="Take reasonable steps to protect PII from misuse",
522
+ remediation="Implement security measures and monitoring",
523
+ ),
524
+ ]
525
+
526
+ def _popia_requirements(self) -> list[ComplianceRequirement]:
527
+ """POPIA (Protection of Personal Information Act) requirements (South Africa)."""
528
+ return [
529
+ ComplianceRequirement(
530
+ regulation=Regulation.POPIA,
531
+ requirement_id="POPIA-10",
532
+ description="Conditions for lawful processing",
533
+ article="Section 10",
534
+ requirement="Process data according to lawful basis",
535
+ remediation="Document legal basis for processing",
536
+ ),
537
+ ComplianceRequirement(
538
+ regulation=Regulation.POPIA,
539
+ requirement_id="POPIA-19",
540
+ description="Data security (Technical and organizational measures)",
541
+ article="Section 19",
542
+ requirement="Implement appropriate security measures",
543
+ remediation="Deploy encryption and access controls",
544
+ ),
545
+ ]
546
+
547
+
548
+ class CrossRegulationComplianceMatrix:
549
+ """Matrix showing compliance overlap across regulations.
550
+
551
+ Shows which requirements apply to multiple regulations,
552
+ enabling efficient compliance management.
553
+ """
554
+
555
+ @staticmethod
556
+ def build_matrix(
557
+ requirements: dict[Regulation, list[ComplianceRequirement]],
558
+ ) -> dict[str, dict[str, bool]]:
559
+ """Build matrix showing which regulations share requirements.
560
+
561
+ Args:
562
+ requirements: Requirements by regulation
563
+
564
+ Returns:
565
+ Matrix: dict[requirement_description][regulation] = bool
566
+ """
567
+ matrix = {}
568
+
569
+ # Common requirement themes across regulations
570
+ themes = {
571
+ "Data Security": ["Encryption", "Access Control", "KMS"],
572
+ "Breach Notification": ["Notify", "Alert", "Incident"],
573
+ "Data Subject Rights": ["Access", "Deletion", "Portability"],
574
+ "Data Minimization": ["Minimize", "Necessary", "Purpose"],
575
+ "Audit Trail": ["Records", "Lineage", "Logging"],
576
+ }
577
+
578
+ for theme, keywords in themes.items():
579
+ matrix[theme] = {}
580
+ for regulation in Regulation:
581
+ reqs = requirements.get(regulation, [])
582
+ # Check if any requirement matches theme
583
+ has_theme = any(
584
+ any(kw.lower() in req.description.lower() for kw in keywords) for req in reqs
585
+ )
586
+ matrix[theme][regulation.value] = has_theme
587
+
588
+ return matrix
589
+
590
+ @staticmethod
591
+ def print_matrix(matrix: dict[str, dict[str, bool]]) -> str:
592
+ """Pretty-print compliance matrix.
593
+
594
+ Args:
595
+ matrix: Compliance matrix
596
+
597
+ Returns:
598
+ Formatted string for display
599
+ """
600
+ regulations = [r.value.upper() for r in Regulation]
601
+ output = []
602
+
603
+ # Header
604
+ output.append("Compliance Requirement Matrix")
605
+ output.append("-" * (20 + len(regulations) * 8))
606
+ output.append(f"{'Requirement':<20} " + " ".join(f"{r:>7}" for r in regulations))
607
+ output.append("-" * (20 + len(regulations) * 8))
608
+
609
+ # Rows
610
+ for requirement, reg_coverage in sorted(matrix.items()):
611
+ row = f"{requirement:<20} "
612
+ for regulation in [r.value for r in Regulation]:
613
+ status = "✓" if reg_coverage.get(regulation, False) else " "
614
+ row += f"{status:>7} "
615
+ output.append(row)
616
+
617
+ return "\n".join(output)