fraiseql-confiture 0.3.4__cp311-cp311-win_amd64.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 (119) hide show
  1. confiture/__init__.py +48 -0
  2. confiture/_core.cp311-win_amd64.pyd +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 +1656 -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 +132 -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 +793 -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 +0 -0
  95. confiture/models/lint.py +193 -0
  96. confiture/models/migration.py +180 -0
  97. confiture/models/schema.py +203 -0
  98. confiture/scenarios/__init__.py +36 -0
  99. confiture/scenarios/compliance.py +586 -0
  100. confiture/scenarios/ecommerce.py +199 -0
  101. confiture/scenarios/financial.py +253 -0
  102. confiture/scenarios/healthcare.py +315 -0
  103. confiture/scenarios/multi_tenant.py +340 -0
  104. confiture/scenarios/saas.py +295 -0
  105. confiture/testing/FRAMEWORK_API.md +722 -0
  106. confiture/testing/__init__.py +38 -0
  107. confiture/testing/fixtures/__init__.py +11 -0
  108. confiture/testing/fixtures/data_validator.py +229 -0
  109. confiture/testing/fixtures/migration_runner.py +167 -0
  110. confiture/testing/fixtures/schema_snapshotter.py +352 -0
  111. confiture/testing/frameworks/__init__.py +10 -0
  112. confiture/testing/frameworks/mutation.py +587 -0
  113. confiture/testing/frameworks/performance.py +479 -0
  114. confiture/testing/utils/__init__.py +0 -0
  115. fraiseql_confiture-0.3.4.dist-info/METADATA +438 -0
  116. fraiseql_confiture-0.3.4.dist-info/RECORD +119 -0
  117. fraiseql_confiture-0.3.4.dist-info/WHEEL +4 -0
  118. fraiseql_confiture-0.3.4.dist-info/entry_points.txt +2 -0
  119. fraiseql_confiture-0.3.4.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,203 @@
1
+ """Data models for schema representation.
2
+
3
+ These models represent database schema objects (tables, columns, indexes, etc.)
4
+ in a structured format for diff detection and comparison.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from enum import Enum
9
+
10
+
11
+ class ColumnType(str, Enum):
12
+ """PostgreSQL column types."""
13
+
14
+ # Integer types
15
+ SMALLINT = "SMALLINT"
16
+ INTEGER = "INTEGER"
17
+ BIGINT = "BIGINT"
18
+ SERIAL = "SERIAL"
19
+ BIGSERIAL = "BIGSERIAL"
20
+
21
+ # Numeric types
22
+ NUMERIC = "NUMERIC"
23
+ DECIMAL = "DECIMAL"
24
+ REAL = "REAL"
25
+ DOUBLE_PRECISION = "DOUBLE PRECISION"
26
+
27
+ # Text types
28
+ VARCHAR = "VARCHAR"
29
+ CHAR = "CHAR"
30
+ TEXT = "TEXT"
31
+
32
+ # Boolean
33
+ BOOLEAN = "BOOLEAN"
34
+
35
+ # Date/Time
36
+ DATE = "DATE"
37
+ TIME = "TIME"
38
+ TIMESTAMP = "TIMESTAMP"
39
+ TIMESTAMPTZ = "TIMESTAMPTZ"
40
+
41
+ # UUID
42
+ UUID = "UUID"
43
+
44
+ # JSON
45
+ JSON = "JSON"
46
+ JSONB = "JSONB"
47
+
48
+ # Binary
49
+ BYTEA = "BYTEA"
50
+
51
+ # Unknown/Custom
52
+ UNKNOWN = "UNKNOWN"
53
+
54
+
55
+ @dataclass
56
+ class Column:
57
+ """Represents a database column."""
58
+
59
+ name: str
60
+ type: ColumnType
61
+ nullable: bool = True
62
+ default: str | None = None
63
+ primary_key: bool = False
64
+ unique: bool = False
65
+ length: int | None = None # For VARCHAR(n), etc.
66
+
67
+ def __eq__(self, other: object) -> bool:
68
+ """Compare columns for equality."""
69
+ if not isinstance(other, Column):
70
+ return NotImplemented
71
+ return (
72
+ self.name == other.name
73
+ and self.type == other.type
74
+ and self.nullable == other.nullable
75
+ and self.default == other.default
76
+ and self.primary_key == other.primary_key
77
+ and self.unique == other.unique
78
+ and self.length == other.length
79
+ )
80
+
81
+ def __hash__(self) -> int:
82
+ """Make column hashable for use in sets."""
83
+ return hash(
84
+ (
85
+ self.name,
86
+ self.type,
87
+ self.nullable,
88
+ self.default,
89
+ self.primary_key,
90
+ self.unique,
91
+ self.length,
92
+ )
93
+ )
94
+
95
+
96
+ @dataclass
97
+ class Table:
98
+ """Represents a database table."""
99
+
100
+ name: str
101
+ columns: list[Column] = field(default_factory=list)
102
+ indexes: list[str] = field(default_factory=list) # Simplified for MVP
103
+ constraints: list[str] = field(default_factory=list) # Simplified for MVP
104
+
105
+ def get_column(self, name: str) -> Column | None:
106
+ """Get column by name."""
107
+ for col in self.columns:
108
+ if col.name == name:
109
+ return col
110
+ return None
111
+
112
+ def has_column(self, name: str) -> bool:
113
+ """Check if table has column."""
114
+ return self.get_column(name) is not None
115
+
116
+ def __eq__(self, other: object) -> bool:
117
+ """Compare tables for equality."""
118
+ if not isinstance(other, Table):
119
+ return NotImplemented
120
+ return (
121
+ self.name == other.name
122
+ and self.columns == other.columns
123
+ and self.indexes == other.indexes
124
+ and self.constraints == other.constraints
125
+ )
126
+
127
+
128
+ @dataclass
129
+ class Schema:
130
+ """Represents a complete database schema."""
131
+
132
+ tables: list[Table] = field(default_factory=list)
133
+
134
+ def get_table(self, name: str) -> Table | None:
135
+ """Get table by name."""
136
+ for table in self.tables:
137
+ if table.name == name:
138
+ return table
139
+ return None
140
+
141
+ def has_table(self, name: str) -> bool:
142
+ """Check if schema has table."""
143
+ return self.get_table(name) is not None
144
+
145
+ def table_names(self) -> list[str]:
146
+ """Get list of all table names."""
147
+ return [table.name for table in self.tables]
148
+
149
+
150
+ @dataclass
151
+ class SchemaChange:
152
+ """Represents a single change between two schemas."""
153
+
154
+ type: str # ADD_TABLE, DROP_TABLE, ADD_COLUMN, etc.
155
+ table: str | None = None
156
+ column: str | None = None
157
+ old_value: str | None = None
158
+ new_value: str | None = None
159
+ details: dict[str, str] | None = None
160
+
161
+ def __str__(self) -> str:
162
+ """String representation of change."""
163
+ if self.type == "ADD_TABLE":
164
+ return f"ADD TABLE {self.table}"
165
+ elif self.type == "DROP_TABLE":
166
+ return f"DROP TABLE {self.table}"
167
+ elif self.type == "RENAME_TABLE":
168
+ return f"RENAME TABLE {self.old_value} TO {self.new_value}"
169
+ elif self.type == "ADD_COLUMN":
170
+ return f"ADD COLUMN {self.table}.{self.column}"
171
+ elif self.type == "DROP_COLUMN":
172
+ return f"DROP COLUMN {self.table}.{self.column}"
173
+ elif self.type == "RENAME_COLUMN":
174
+ return f"RENAME COLUMN {self.table}.{self.old_value} TO {self.new_value}"
175
+ elif self.type == "CHANGE_COLUMN_TYPE":
176
+ return f"CHANGE COLUMN TYPE {self.table}.{self.column} FROM {self.old_value} TO {self.new_value}"
177
+ elif self.type == "CHANGE_COLUMN_NULLABLE":
178
+ return f"CHANGE COLUMN NULLABLE {self.table}.{self.column} FROM {self.old_value} TO {self.new_value}"
179
+ elif self.type == "CHANGE_COLUMN_DEFAULT":
180
+ return f"CHANGE COLUMN DEFAULT {self.table}.{self.column}"
181
+ else:
182
+ return f"{self.type}: {self.table}.{self.column if self.column else ''}"
183
+
184
+
185
+ @dataclass
186
+ class SchemaDiff:
187
+ """Represents the difference between two schemas."""
188
+
189
+ changes: list[SchemaChange] = field(default_factory=list)
190
+
191
+ def has_changes(self) -> bool:
192
+ """Check if there are any changes."""
193
+ return len(self.changes) > 0
194
+
195
+ def count_by_type(self, change_type: str) -> int:
196
+ """Count changes of a specific type."""
197
+ return sum(1 for c in self.changes if c.type == change_type)
198
+
199
+ def __str__(self) -> str:
200
+ """String representation of diff."""
201
+ if not self.has_changes():
202
+ return "No changes detected"
203
+ return "\n".join(str(c) for c in self.changes)
@@ -0,0 +1,36 @@
1
+ """Real-world anonymization scenarios.
2
+
3
+ Provides ready-to-use anonymization profiles for common business domains:
4
+ - E-commerce: Customer data, orders, payments
5
+ - Healthcare: HIPAA-compliant PHI anonymization
6
+ - Financial: Loan applications, credit data
7
+ - SaaS: User accounts, subscription data
8
+ - Multi-tenant: Data isolation with deterministic seeding
9
+
10
+ Each scenario includes:
11
+ - Pre-configured strategy profiles
12
+ - Batch anonymization support
13
+ - Domain-specific validation
14
+ - Usage examples
15
+
16
+ Usage:
17
+ >>> from confiture.scenarios import ECommerceScenario
18
+ >>> data = {"first_name": "John", "email": "john@example.com"}
19
+ >>> anonymized = ECommerceScenario.anonymize(data)
20
+ """
21
+
22
+ # Import strategies to ensure registration (must come before scenario imports)
23
+ import confiture.core.anonymization.strategies # noqa: F401
24
+ from confiture.scenarios.ecommerce import ECommerceScenario
25
+ from confiture.scenarios.financial import FinancialScenario
26
+ from confiture.scenarios.healthcare import HealthcareScenario
27
+ from confiture.scenarios.multi_tenant import MultiTenantScenario
28
+ from confiture.scenarios.saas import SaaSScenario
29
+
30
+ __all__ = [
31
+ "ECommerceScenario",
32
+ "HealthcareScenario",
33
+ "FinancialScenario",
34
+ "SaaSScenario",
35
+ "MultiTenantScenario",
36
+ ]