bauta 0.1.0__tar.gz

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 (76) hide show
  1. bauta-0.1.0/LICENSE +21 -0
  2. bauta-0.1.0/PKG-INFO +211 -0
  3. bauta-0.1.0/README.md +156 -0
  4. bauta-0.1.0/bauta/__init__.py +93 -0
  5. bauta-0.1.0/bauta/audit.py +319 -0
  6. bauta-0.1.0/bauta/builtinTransforms.py +373 -0
  7. bauta-0.1.0/bauta/cli.py +1106 -0
  8. bauta-0.1.0/bauta/configuration.py +521 -0
  9. bauta-0.1.0/bauta/database.py +396 -0
  10. bauta-0.1.0/bauta/databaseDialects.py +1153 -0
  11. bauta-0.1.0/bauta/dependencyGraph.py +127 -0
  12. bauta-0.1.0/bauta/discovery.py +402 -0
  13. bauta-0.1.0/bauta/fpe.py +118 -0
  14. bauta-0.1.0/bauta/log.py +218 -0
  15. bauta-0.1.0/bauta/masking.py +1704 -0
  16. bauta-0.1.0/bauta/memory.py +357 -0
  17. bauta-0.1.0/bauta/py.typed +0 -0
  18. bauta-0.1.0/bauta/reporting.py +358 -0
  19. bauta-0.1.0/bauta/runner.py +762 -0
  20. bauta-0.1.0/bauta/schema.py +408 -0
  21. bauta-0.1.0/bauta/scrubbing.py +115 -0
  22. bauta-0.1.0/bauta/subset.py +289 -0
  23. bauta-0.1.0/bauta/synthesize.py +428 -0
  24. bauta-0.1.0/bauta/transform.py +164 -0
  25. bauta-0.1.0/bauta.egg-info/PKG-INFO +211 -0
  26. bauta-0.1.0/bauta.egg-info/SOURCES.txt +74 -0
  27. bauta-0.1.0/bauta.egg-info/dependency_links.txt +1 -0
  28. bauta-0.1.0/bauta.egg-info/entry_points.txt +2 -0
  29. bauta-0.1.0/bauta.egg-info/requires.txt +32 -0
  30. bauta-0.1.0/bauta.egg-info/top_level.txt +1 -0
  31. bauta-0.1.0/pyproject.toml +87 -0
  32. bauta-0.1.0/setup.cfg +4 -0
  33. bauta-0.1.0/tests/test_audit.py +252 -0
  34. bauta-0.1.0/tests/test_builtinTransforms.py +156 -0
  35. bauta-0.1.0/tests/test_cli.py +871 -0
  36. bauta-0.1.0/tests/test_configuration.py +333 -0
  37. bauta-0.1.0/tests/test_database.py +393 -0
  38. bauta-0.1.0/tests/test_databaseDialects.py +451 -0
  39. bauta-0.1.0/tests/test_dependencyGraph.py +216 -0
  40. bauta-0.1.0/tests/test_discovery.py +181 -0
  41. bauta-0.1.0/tests/test_documentation.py +114 -0
  42. bauta-0.1.0/tests/test_environmentVariables.py +182 -0
  43. bauta-0.1.0/tests/test_fpe.py +52 -0
  44. bauta-0.1.0/tests/test_incremental_demo.py +106 -0
  45. bauta-0.1.0/tests/test_integration_connections.py +125 -0
  46. bauta-0.1.0/tests/test_integration_cross_database.py +103 -0
  47. bauta-0.1.0/tests/test_integration_keys.py +243 -0
  48. bauta-0.1.0/tests/test_integration_mariadb.py +203 -0
  49. bauta-0.1.0/tests/test_integration_masking.py +248 -0
  50. bauta-0.1.0/tests/test_integration_mssql.py +353 -0
  51. bauta-0.1.0/tests/test_integration_mysql.py +304 -0
  52. bauta-0.1.0/tests/test_integration_oracle.py +299 -0
  53. bauta-0.1.0/tests/test_integration_postgresql.py +380 -0
  54. bauta-0.1.0/tests/test_integration_schema.py +187 -0
  55. bauta-0.1.0/tests/test_integration_scrubbing.py +136 -0
  56. bauta-0.1.0/tests/test_integration_sqlite.py +281 -0
  57. bauta-0.1.0/tests/test_integration_synthesize.py +70 -0
  58. bauta-0.1.0/tests/test_lazy_driver_imports.py +39 -0
  59. bauta-0.1.0/tests/test_log.py +199 -0
  60. bauta-0.1.0/tests/test_maskVectors.py +58 -0
  61. bauta-0.1.0/tests/test_masking.py +1055 -0
  62. bauta-0.1.0/tests/test_masking_demo.py +84 -0
  63. bauta-0.1.0/tests/test_masking_end_to_end.py +195 -0
  64. bauta-0.1.0/tests/test_memory.py +270 -0
  65. bauta-0.1.0/tests/test_nativeMasking.py +145 -0
  66. bauta-0.1.0/tests/test_native_masking_demo.py +65 -0
  67. bauta-0.1.0/tests/test_packaging.py +73 -0
  68. bauta-0.1.0/tests/test_reporting.py +183 -0
  69. bauta-0.1.0/tests/test_runner.py +1520 -0
  70. bauta-0.1.0/tests/test_schema.py +274 -0
  71. bauta-0.1.0/tests/test_scrubbing.py +213 -0
  72. bauta-0.1.0/tests/test_shipped_example_configuration.py +132 -0
  73. bauta-0.1.0/tests/test_subset.py +254 -0
  74. bauta-0.1.0/tests/test_synthesize.py +147 -0
  75. bauta-0.1.0/tests/test_transform.py +158 -0
  76. bauta-0.1.0/tests/test_walkthrough.py +83 -0
bauta-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David Ribeiro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
bauta-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: bauta
3
+ Version: 0.1.0
4
+ Summary: Safe, realistic copies of production across databases: masking, subsets, synthetic data, and the ETL to move them
5
+ Author: David Ribeiro
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ribeiro11075/bauta
8
+ Project-URL: Documentation, https://github.com/ribeiro11075/bauta/tree/master/docs
9
+ Project-URL: Issues, https://github.com/ribeiro11075/bauta/issues
10
+ Keywords: data masking,test data,anonymization,pseudonymization,database subsetting,synthetic data,etl,format-preserving encryption,oracle,sql server,postgresql,mysql
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Database
25
+ Classifier: Topic :: Security
26
+ Classifier: Topic :: Software Development :: Testing
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: pyyaml<7,>=6.0.1
32
+ Requires-Dist: pydantic<3,>=2.6
33
+ Provides-Extra: mysql
34
+ Requires-Dist: mysql-connector-python>=8.4; extra == "mysql"
35
+ Provides-Extra: postgresql
36
+ Requires-Dist: psycopg2>=2.9.6; extra == "postgresql"
37
+ Provides-Extra: oracle
38
+ Requires-Dist: oracledb>=2.5; extra == "oracle"
39
+ Provides-Extra: mssql
40
+ Requires-Dist: pymssql>=2.3.5; extra == "mssql"
41
+ Provides-Extra: mariadb
42
+ Requires-Dist: mysql-connector-python>=8.4; extra == "mariadb"
43
+ Provides-Extra: sqlite
44
+ Provides-Extra: fpe
45
+ Requires-Dist: cryptography>=42; extra == "fpe"
46
+ Provides-Extra: all
47
+ Requires-Dist: bauta[fpe,mariadb,mssql,mysql,oracle,postgresql,sqlite]; extra == "all"
48
+ Provides-Extra: dev
49
+ Requires-Dist: pytest==9.1.1; extra == "dev"
50
+ Requires-Dist: mypy==2.3.1; extra == "dev"
51
+ Requires-Dist: types-PyYAML==6.0.12.20260815; extra == "dev"
52
+ Requires-Dist: build==1.6.1; extra == "dev"
53
+ Requires-Dist: twine==7.0.0; extra == "dev"
54
+ Dynamic: license-file
55
+
56
+ # Bauta
57
+
58
+ **Put a mask on production:** a safe, realistic stand-in for your production data, in whichever database you need it. Bauta masks what it copies, copies only the slice you need with every relationship intact, generates what may not be copied at all, and moves data between databases on a schedule you already run, with nothing to host.
59
+
60
+ - **Masking:** consistent across tables and runs, one-to-one for keys (NIST FF1 where policy requires it), applied before anything reaches the target, and every column must be covered.
61
+ - **Discovery, subsets and synthetic data:** propose a masking policy from a live schema, copy a referentially complete slice of production, create the copy's tables in whichever database it goes to, and fill tables that can't be copied with generated rows.
62
+ - **Audit:** report what every job does with data and what a reviewer should question, and seal each run's masking manifest so it can be verified later.
63
+ - **Six databases:** Oracle, SQL Server, PostgreSQL, MySQL, MariaDB and SQLite, as source or target in any combination.
64
+ - **Streaming:** memory stays flat however large the table, and PostgreSQL and SQL Server targets load in bulk.
65
+ - **Fast:** ten million rows of six masked columns in under two minutes on one core with the optional native masker, and under eight without. Either way the masks are the same.
66
+ - **Incremental loads:** extract only what changed since the last successful run.
67
+ - **A dependency graph:** jobs run in order, concurrently where they can, each in its own process with an optional timeout.
68
+ - **Operable:** run history, Prometheus metrics, webhook alerts, run state in a file or a table, and passwords from a command for cloud IAM tokens.
69
+ - **No infrastructure:** a `pip install`, some YAML, and a command you run from cron.
70
+
71
+
72
+ ## Install
73
+
74
+ Python 3.10 or newer. Choose the drivers you need as extras; each is loaded only when a connection uses it.
75
+
76
+ ```
77
+ pip install "bauta[postgresql,oracle]"
78
+ ```
79
+
80
+ It isn't on PyPI yet. Until the first release, install from a clone:
81
+
82
+ ```
83
+ git clone https://github.com/ribeiro11075/bauta.git
84
+ cd bauta
85
+ pip install -e ".[postgresql,oracle]"
86
+ ```
87
+
88
+ | Extra | Driver | Needs besides pip |
89
+ | --- | --- | --- |
90
+ | `mysql`, `mariadb` | mysql-connector-python | nothing |
91
+ | `postgresql` | psycopg2, built from source | a C compiler and PostgreSQL's client library (below) |
92
+ | `oracle` | oracledb, in thin mode | nothing — no Oracle client |
93
+ | `mssql` | pymssql | nothing |
94
+ | `sqlite` | Python's own `sqlite3` | nothing |
95
+ | `fpe` | cryptography, for the `fpe` masking strategy | nothing; `oracle` already brings it |
96
+ | `all` | every driver above | as for `postgresql` |
97
+
98
+ **Building psycopg2.** pip compiles it, so it needs a compiler and `pg_config`:
99
+
100
+ - macOS: `xcode-select --install`, then `brew install libpq` and `export PATH="$(brew --prefix libpq)/bin:$PATH"` (Homebrew doesn't put libpq on the path by itself).
101
+ - Debian or Ubuntu: `apt install build-essential libpq-dev`.
102
+
103
+ To skip the build, leave `postgresql` (and `all`) out and install the prebuilt driver beside the other extras: `pip install "bauta[mysql,oracle,mssql]" psycopg2-binary`. psycopg2's maintainers recommend the source build for production.
104
+
105
+ **The native masker (optional).** `bauta-rs`, in `mask-rs/`, masks in Rust: four to five times the throughput, identical masks, nothing to configure. With [Rust](https://rustup.rs) 1.83 or newer, pip builds it in the same command as the rest:
106
+
107
+ ```
108
+ pip install -e ".[all]" ./mask-rs/py
109
+ ```
110
+
111
+ Without Rust, leave `./mask-rs/py` off; everything works, only slower. See [the native masker](docs/masking.md#the-native-masker).
112
+
113
+
114
+ ## Quickstart
115
+
116
+ ```
117
+ mkdir configuration
118
+ cp example/starter/configuration/*.yaml configuration/
119
+ ```
120
+
121
+ Edit `configuration/database.yaml` and `configuration/jobs.yaml` for your databases, then supply the credentials they reference:
122
+
123
+ ```
124
+ export SOURCE_DB_PASSWORD=... TARGET_DB_PASSWORD=... MASKING_KEY=...
125
+
126
+ bauta validate # check the configuration, offline
127
+ bauta run --dry-run # check connections and tables, moving nothing
128
+ bauta run # run every job once
129
+ ```
130
+
131
+ To see it work without any of that, using throwaway SQLite databases:
132
+
133
+ ```
134
+ python example/walkthrough/demo.py # the whole workflow: discover, subset, audit, mask, verify, synthesize
135
+ python example/incremental/demo.py # streaming and incremental loads
136
+ python example/masking/demo.py # masking, discovery and a subset, from Python
137
+ python example/native-masking/demo.py # the same job masked in Python and in Rust, compared
138
+ ```
139
+
140
+
141
+ ## The command
142
+
143
+ ```
144
+ bauta run run data jobs once, masking any with a `masking` section
145
+ bauta validate check configuration without connecting
146
+ bauta jobs show the job graph and what's due
147
+ bauta history show recent job outcomes recorded with --history
148
+
149
+ bauta discover propose a masking policy for tables
150
+ bauta subset generate jobs that copy a referentially complete subset
151
+ bauta schema create target tables from source ones, in the target's dialect
152
+ bauta synthesize fill tables with generated rows, for data that can't be copied
153
+ bauta clear empty the target tables of jobs, children first
154
+
155
+ bauta audit report what each job does with data, and what to question
156
+ bauta verify-manifest check a manifest is unaltered, and who signed it
157
+ ```
158
+
159
+ | Exit code | Meaning |
160
+ | --- | --- |
161
+ | `0` | every job completed |
162
+ | `1` | a job failed, or was skipped because a predecessor failed, or the command failed on a database error |
163
+ | `2` | invalid configuration or usage |
164
+ | `130` | interrupted by a signal: running jobs finished, the rest were skipped |
165
+
166
+ `run` makes one pass and exits, so it fits under cron or a Kubernetes CronJob. A second `run` sharing the same run state refuses to start while the first is still going. The useful flags:
167
+
168
+ | Flag | |
169
+ | --- | --- |
170
+ | `--config DIR` | where the YAML lives; default `./configuration` |
171
+ | `--job NAME` | run only this job — without its predecessors, which it warns about |
172
+ | `--force` | ignore `refresh` windows |
173
+ | `--forever` | stay running; for freshness under a minute |
174
+ | `--log-format json` | structured logs for a collector |
175
+ | `--log FILE` | also log to a file, in addition to stderr (`--quiet` silences stderr) |
176
+ | `--memory FILE` | where run state (last runs, watermarks) is kept, overriding `jobs.yaml`'s [`memory`](docs/configuration.md#file-level) |
177
+ | `--memory-database ALIAS` | keep run state in a database table instead |
178
+ | `--history FILE` | append each job's outcome to a JSON-lines history |
179
+ | `--metrics FILE` | write Prometheus metrics for the textfile collector (`--metrics-push URL` for a Pushgateway) |
180
+ | `--notify-url URL` | post to a webhook when a run doesn't succeed; default `$BAUTA_NOTIFY_URL` |
181
+ | `--accept-key-change` | run upsert jobs whose masking key changed since their last run |
182
+ | `--manifest FILE` | write a sealed JSON record of what was masked, and how; signed if `$BAUTA_MANIFEST_KEY` is set |
183
+
184
+
185
+ ## Documentation
186
+
187
+ | | |
188
+ | --- | --- |
189
+ | [Configuration](docs/configuration.md) | every field, how credentials are read from the environment, and connection options such as TLS |
190
+ | [Masking](docs/masking.md) | strategies, consistent masks across tables, the key, the manifest, `audit`, `discover`, `subset`, `schema`, `synthesize` and `clear` |
191
+ | [How it works](docs/design.md) | streaming, incremental loads, retries, scheduling, and the masking design |
192
+ | [Operating it](docs/operations.md) | run state, history, metrics and notifications |
193
+ | [Security model](docs/security.md) | what masking protects and what it doesn't, the constructions, keys, and a deployment checklist |
194
+ | [Library](docs/library.md) | embedding it in Python, results, memory backends |
195
+ | [Development](docs/development.md) | running the tests, including against real databases |
196
+
197
+
198
+ ## Layout
199
+
200
+ | | |
201
+ | --- | --- |
202
+ | `bauta/` | the package; `runner.py` runs jobs, `masking.py` masks, `databaseDialects.py` holds per-database SQL |
203
+ | `mask-rs/` | the optional native masker, in Rust — see [its README](mask-rs/README.md) |
204
+ | `example/` | runnable demos, each with its `configuration/`, and a starter configuration — see [its README](example/README.md) |
205
+ | `docs/` | the documentation above |
206
+ | `tests/` | the test suite |
207
+
208
+
209
+ ## License
210
+
211
+ [MIT](LICENSE)
bauta-0.1.0/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # Bauta
2
+
3
+ **Put a mask on production:** a safe, realistic stand-in for your production data, in whichever database you need it. Bauta masks what it copies, copies only the slice you need with every relationship intact, generates what may not be copied at all, and moves data between databases on a schedule you already run, with nothing to host.
4
+
5
+ - **Masking:** consistent across tables and runs, one-to-one for keys (NIST FF1 where policy requires it), applied before anything reaches the target, and every column must be covered.
6
+ - **Discovery, subsets and synthetic data:** propose a masking policy from a live schema, copy a referentially complete slice of production, create the copy's tables in whichever database it goes to, and fill tables that can't be copied with generated rows.
7
+ - **Audit:** report what every job does with data and what a reviewer should question, and seal each run's masking manifest so it can be verified later.
8
+ - **Six databases:** Oracle, SQL Server, PostgreSQL, MySQL, MariaDB and SQLite, as source or target in any combination.
9
+ - **Streaming:** memory stays flat however large the table, and PostgreSQL and SQL Server targets load in bulk.
10
+ - **Fast:** ten million rows of six masked columns in under two minutes on one core with the optional native masker, and under eight without. Either way the masks are the same.
11
+ - **Incremental loads:** extract only what changed since the last successful run.
12
+ - **A dependency graph:** jobs run in order, concurrently where they can, each in its own process with an optional timeout.
13
+ - **Operable:** run history, Prometheus metrics, webhook alerts, run state in a file or a table, and passwords from a command for cloud IAM tokens.
14
+ - **No infrastructure:** a `pip install`, some YAML, and a command you run from cron.
15
+
16
+
17
+ ## Install
18
+
19
+ Python 3.10 or newer. Choose the drivers you need as extras; each is loaded only when a connection uses it.
20
+
21
+ ```
22
+ pip install "bauta[postgresql,oracle]"
23
+ ```
24
+
25
+ It isn't on PyPI yet. Until the first release, install from a clone:
26
+
27
+ ```
28
+ git clone https://github.com/ribeiro11075/bauta.git
29
+ cd bauta
30
+ pip install -e ".[postgresql,oracle]"
31
+ ```
32
+
33
+ | Extra | Driver | Needs besides pip |
34
+ | --- | --- | --- |
35
+ | `mysql`, `mariadb` | mysql-connector-python | nothing |
36
+ | `postgresql` | psycopg2, built from source | a C compiler and PostgreSQL's client library (below) |
37
+ | `oracle` | oracledb, in thin mode | nothing — no Oracle client |
38
+ | `mssql` | pymssql | nothing |
39
+ | `sqlite` | Python's own `sqlite3` | nothing |
40
+ | `fpe` | cryptography, for the `fpe` masking strategy | nothing; `oracle` already brings it |
41
+ | `all` | every driver above | as for `postgresql` |
42
+
43
+ **Building psycopg2.** pip compiles it, so it needs a compiler and `pg_config`:
44
+
45
+ - macOS: `xcode-select --install`, then `brew install libpq` and `export PATH="$(brew --prefix libpq)/bin:$PATH"` (Homebrew doesn't put libpq on the path by itself).
46
+ - Debian or Ubuntu: `apt install build-essential libpq-dev`.
47
+
48
+ To skip the build, leave `postgresql` (and `all`) out and install the prebuilt driver beside the other extras: `pip install "bauta[mysql,oracle,mssql]" psycopg2-binary`. psycopg2's maintainers recommend the source build for production.
49
+
50
+ **The native masker (optional).** `bauta-rs`, in `mask-rs/`, masks in Rust: four to five times the throughput, identical masks, nothing to configure. With [Rust](https://rustup.rs) 1.83 or newer, pip builds it in the same command as the rest:
51
+
52
+ ```
53
+ pip install -e ".[all]" ./mask-rs/py
54
+ ```
55
+
56
+ Without Rust, leave `./mask-rs/py` off; everything works, only slower. See [the native masker](docs/masking.md#the-native-masker).
57
+
58
+
59
+ ## Quickstart
60
+
61
+ ```
62
+ mkdir configuration
63
+ cp example/starter/configuration/*.yaml configuration/
64
+ ```
65
+
66
+ Edit `configuration/database.yaml` and `configuration/jobs.yaml` for your databases, then supply the credentials they reference:
67
+
68
+ ```
69
+ export SOURCE_DB_PASSWORD=... TARGET_DB_PASSWORD=... MASKING_KEY=...
70
+
71
+ bauta validate # check the configuration, offline
72
+ bauta run --dry-run # check connections and tables, moving nothing
73
+ bauta run # run every job once
74
+ ```
75
+
76
+ To see it work without any of that, using throwaway SQLite databases:
77
+
78
+ ```
79
+ python example/walkthrough/demo.py # the whole workflow: discover, subset, audit, mask, verify, synthesize
80
+ python example/incremental/demo.py # streaming and incremental loads
81
+ python example/masking/demo.py # masking, discovery and a subset, from Python
82
+ python example/native-masking/demo.py # the same job masked in Python and in Rust, compared
83
+ ```
84
+
85
+
86
+ ## The command
87
+
88
+ ```
89
+ bauta run run data jobs once, masking any with a `masking` section
90
+ bauta validate check configuration without connecting
91
+ bauta jobs show the job graph and what's due
92
+ bauta history show recent job outcomes recorded with --history
93
+
94
+ bauta discover propose a masking policy for tables
95
+ bauta subset generate jobs that copy a referentially complete subset
96
+ bauta schema create target tables from source ones, in the target's dialect
97
+ bauta synthesize fill tables with generated rows, for data that can't be copied
98
+ bauta clear empty the target tables of jobs, children first
99
+
100
+ bauta audit report what each job does with data, and what to question
101
+ bauta verify-manifest check a manifest is unaltered, and who signed it
102
+ ```
103
+
104
+ | Exit code | Meaning |
105
+ | --- | --- |
106
+ | `0` | every job completed |
107
+ | `1` | a job failed, or was skipped because a predecessor failed, or the command failed on a database error |
108
+ | `2` | invalid configuration or usage |
109
+ | `130` | interrupted by a signal: running jobs finished, the rest were skipped |
110
+
111
+ `run` makes one pass and exits, so it fits under cron or a Kubernetes CronJob. A second `run` sharing the same run state refuses to start while the first is still going. The useful flags:
112
+
113
+ | Flag | |
114
+ | --- | --- |
115
+ | `--config DIR` | where the YAML lives; default `./configuration` |
116
+ | `--job NAME` | run only this job — without its predecessors, which it warns about |
117
+ | `--force` | ignore `refresh` windows |
118
+ | `--forever` | stay running; for freshness under a minute |
119
+ | `--log-format json` | structured logs for a collector |
120
+ | `--log FILE` | also log to a file, in addition to stderr (`--quiet` silences stderr) |
121
+ | `--memory FILE` | where run state (last runs, watermarks) is kept, overriding `jobs.yaml`'s [`memory`](docs/configuration.md#file-level) |
122
+ | `--memory-database ALIAS` | keep run state in a database table instead |
123
+ | `--history FILE` | append each job's outcome to a JSON-lines history |
124
+ | `--metrics FILE` | write Prometheus metrics for the textfile collector (`--metrics-push URL` for a Pushgateway) |
125
+ | `--notify-url URL` | post to a webhook when a run doesn't succeed; default `$BAUTA_NOTIFY_URL` |
126
+ | `--accept-key-change` | run upsert jobs whose masking key changed since their last run |
127
+ | `--manifest FILE` | write a sealed JSON record of what was masked, and how; signed if `$BAUTA_MANIFEST_KEY` is set |
128
+
129
+
130
+ ## Documentation
131
+
132
+ | | |
133
+ | --- | --- |
134
+ | [Configuration](docs/configuration.md) | every field, how credentials are read from the environment, and connection options such as TLS |
135
+ | [Masking](docs/masking.md) | strategies, consistent masks across tables, the key, the manifest, `audit`, `discover`, `subset`, `schema`, `synthesize` and `clear` |
136
+ | [How it works](docs/design.md) | streaming, incremental loads, retries, scheduling, and the masking design |
137
+ | [Operating it](docs/operations.md) | run state, history, metrics and notifications |
138
+ | [Security model](docs/security.md) | what masking protects and what it doesn't, the constructions, keys, and a deployment checklist |
139
+ | [Library](docs/library.md) | embedding it in Python, results, memory backends |
140
+ | [Development](docs/development.md) | running the tests, including against real databases |
141
+
142
+
143
+ ## Layout
144
+
145
+ | | |
146
+ | --- | --- |
147
+ | `bauta/` | the package; `runner.py` runs jobs, `masking.py` masks, `databaseDialects.py` holds per-database SQL |
148
+ | `mask-rs/` | the optional native masker, in Rust — see [its README](mask-rs/README.md) |
149
+ | `example/` | runnable demos, each with its `configuration/`, and a starter configuration — see [its README](example/README.md) |
150
+ | `docs/` | the documentation above |
151
+ | `tests/` | the test suite |
152
+
153
+
154
+ ## License
155
+
156
+ [MIT](LICENSE)
@@ -0,0 +1,93 @@
1
+ from .configuration import (
2
+ BaseJobConfig,
3
+ Configuration,
4
+ ConfigurationError,
5
+ DatabaseConnectionConfig,
6
+ DatabaseType,
7
+ DataJobConfig,
8
+ DataJobsFile,
9
+ InsertStrategy,
10
+ MaskingConfig,
11
+ expandEnvironmentVariables,
12
+ )
13
+ from .databaseDialects import ColumnCategory, DatabaseDialect, ForeignKey, MariaDBDialect, MSSQLDialect, MySQLDialect, OracleDialect, PostgreSQLDialect, SQLiteDialect
14
+ from .database import Database
15
+ from .dependencyGraph import DependencyGraph, JobOutcome, JobStatus
16
+ from .discovery import TableProposal, proposeTable
17
+ from .log import Log
18
+ from .audit import auditJobs, renderAudit
19
+ from .masking import LOCALES, STRATEGIES, MaskingError, MaskingPlan, Strategy, buildMaskingManifest, keyFingerprint, resolveStrategy, sealManifest, \
20
+ verifyManifest
21
+ from .memory import DATABASE_MEMORY_SCHEMA, DatabaseMemory, FileMemory, MemoryBackend, RunInProgressError, exclusiveRun
22
+ from .reporting import DATABASE_HISTORY_SCHEMA, DatabaseHistory, FileHistory, RunHistory, notify, pushMetrics, writeMetricsFile
23
+ from .runner import RunResult, runDataJobs
24
+ from .subset import SubsetError, SubsetPlan, planSubset
25
+ from .synthesize import SynthesisError, planTable, synthesizeTable
26
+ from .transform import Transform, Transformer, TransformError, TransformResolutionError, resolveTransformer
27
+
28
+ __all__ = [
29
+ 'auditJobs',
30
+ 'BaseJobConfig',
31
+ 'buildMaskingManifest',
32
+ 'ColumnCategory',
33
+ 'Configuration',
34
+ 'ConfigurationError',
35
+ 'DATABASE_HISTORY_SCHEMA',
36
+ 'DATABASE_MEMORY_SCHEMA',
37
+ 'DatabaseHistory',
38
+ 'Database',
39
+ 'DatabaseConnectionConfig',
40
+ 'DatabaseDialect',
41
+ 'DatabaseMemory',
42
+ 'DatabaseType',
43
+ 'exclusiveRun',
44
+ 'expandEnvironmentVariables',
45
+ 'DataJobConfig',
46
+ 'DataJobsFile',
47
+ 'DependencyGraph',
48
+ 'FileHistory',
49
+ 'FileMemory',
50
+ 'ForeignKey',
51
+ 'InsertStrategy',
52
+ 'JobOutcome',
53
+ 'JobStatus',
54
+ 'keyFingerprint',
55
+ 'LOCALES',
56
+ 'Log',
57
+ 'MariaDBDialect',
58
+ 'MaskingConfig',
59
+ 'MaskingError',
60
+ 'MaskingPlan',
61
+ 'MemoryBackend',
62
+ 'MSSQLDialect',
63
+ 'notify',
64
+ 'MySQLDialect',
65
+ 'OracleDialect',
66
+ 'planSubset',
67
+ 'PostgreSQLDialect',
68
+ 'proposeTable',
69
+ 'pushMetrics',
70
+ 'RunHistory',
71
+ 'RunInProgressError',
72
+ 'RunResult',
73
+ 'SQLiteDialect',
74
+ 'STRATEGIES',
75
+ 'Strategy',
76
+ 'SubsetError',
77
+ 'SubsetPlan',
78
+ 'SynthesisError',
79
+ 'synthesizeTable',
80
+ 'planTable',
81
+ 'TableProposal',
82
+ 'Transform',
83
+ 'Transformer',
84
+ 'TransformError',
85
+ 'TransformResolutionError',
86
+ 'renderAudit',
87
+ 'resolveStrategy',
88
+ 'resolveTransformer',
89
+ 'sealManifest',
90
+ 'verifyManifest',
91
+ 'writeMetricsFile',
92
+ 'runDataJobs',
93
+ ]