@rehearsal-db/core 0.1.0-beta.1 → 0.1.0-beta.10
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.
- package/CHANGELOG.md +244 -1
- package/COMPATIBILITY.md +17 -0
- package/README.md +139 -346
- package/SECURITY.md +2 -1
- package/SUPPORT.md +5 -0
- package/docs/README.md +29 -0
- package/docs/adapters.md +20 -6
- package/docs/architecture.md +58 -0
- package/docs/baselines.md +102 -22
- package/docs/commands.md +196 -33
- package/docs/configuration.md +258 -13
- package/docs/getting-started.md +106 -182
- package/docs/glossary.md +11 -8
- package/docs/production-source.md +176 -33
- package/docs/releasing.md +28 -38
- package/docs/roadmap.md +41 -0
- package/docs/runtime-policies.md +193 -0
- package/docs/sanitization.md +43 -8
- package/docs/security-model.md +34 -9
- package/docs/standalone-workflow.md +107 -0
- package/docs/troubleshooting.md +102 -2
- package/docs/tutorial.md +70 -59
- package/package.json +30 -22
- package/scripts/runtime/manage_database.mjs +18 -0
- package/src/README.md +17 -0
- package/src/application/session.mjs +435 -0
- package/{scripts/lib/rehearsal/baseline_artifact.mjs → src/baseline/artifact.mjs} +142 -17
- package/{scripts/lib/rehearsal/baseline_builder.mjs → src/baseline/builder.mjs} +19 -10
- package/src/baseline/input_discovery.mjs +155 -0
- package/src/baseline/policy_review.mjs +92 -0
- package/src/baseline/preparation.mjs +323 -0
- package/src/baseline/privacy_engine.mjs +413 -0
- package/{scripts/lib/rehearsal → src/baseline}/sanitization_policy.mjs +133 -3
- package/{scripts/lib/rehearsal → src/baseline}/schema_snapshot.mjs +1 -1
- package/src/cli/arguments.mjs +123 -0
- package/src/cli/guided.mjs +812 -0
- package/src/cli/rehearsal.mjs +997 -0
- package/src/cli/renderers.mjs +584 -0
- package/src/cli/runtime_commands.mjs +624 -0
- package/src/cli/source_commands.mjs +326 -0
- package/src/cli/terminal.mjs +275 -0
- package/src/identity/claim.mjs +975 -0
- package/src/identity/storage.mjs +165 -0
- package/{scripts/lib/rehearsal → src/project}/configuration.d.mts +72 -4
- package/src/project/configuration.mjs +1199 -0
- package/src/project/setup.mjs +379 -0
- package/src/project/support_report.mjs +105 -0
- package/src/runtime/cleanup.mjs +381 -0
- package/{scripts/lib/rehearsal → src/runtime}/plan.mjs +118 -20
- package/src/runtime/policy.mjs +438 -0
- package/{scripts/lib/rehearsal/runtime_restore.mjs → src/runtime/restore.mjs} +46 -27
- package/src/runtime/topology.mjs +177 -0
- package/{scripts/lib/rehearsal → src/shared}/diagnostics.mjs +10 -3
- package/src/shared/human_output.mjs +4 -0
- package/src/shared/operation_guard.mjs +162 -0
- package/{scripts/lib/rehearsal → src/shared}/process_environment.mjs +5 -1
- package/src/source/access.mjs +578 -0
- package/src/source/asset_transfer.mjs +177 -0
- package/src/source/baseline.mjs +446 -0
- package/src/source/postgresql_access.mjs +480 -0
- package/src/targets/postgresql.mjs +808 -0
- package/{scripts/operations/database/manage_rehearsal_database.mjs → src/targets/supabase.mjs} +66 -20
- package/{scripts/lib/environment/local_supabase.mjs → src/targets/supabase_environment.mjs} +60 -28
- package/src/targets/target.mjs +66 -0
- package/scripts/lib/rehearsal/configuration.mjs +0 -559
- package/scripts/operations/rehearsal/rehearsal_cli.mjs +0 -565
- /package/{scripts/lib/rehearsal → src/runtime}/migration_history.mjs +0 -0
- /package/{scripts/lib/rehearsal → src/runtime}/service_environment.mjs +0 -0
package/docs/getting-started.md
CHANGED
|
@@ -1,247 +1,171 @@
|
|
|
1
1
|
# Getting started
|
|
2
2
|
|
|
3
|
-
This guide
|
|
4
|
-
|
|
3
|
+
This guide sets up Rehearsal in an existing project. It creates a disposable database on
|
|
4
|
+
your computer. Normal setup and rehearsal commands never connect to a hosted database.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Want to experiment first? Use the [safe hands-on tutorial](tutorial.md).
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
- npm
|
|
10
|
-
- Supabase CLI 2.117.0 (the version proved by package CI)
|
|
11
|
-
- Docker Desktop, Colima, or another Docker-compatible engine
|
|
12
|
-
- a Supabase project with timestamped SQL migrations
|
|
8
|
+
## 1. Check the required tools
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
You need Node.js 24, npm, and a running Docker-compatible engine:
|
|
15
11
|
|
|
16
12
|
```bash
|
|
17
13
|
node --version
|
|
18
14
|
npm --version
|
|
19
|
-
supabase --version
|
|
20
15
|
docker info
|
|
21
16
|
```
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
`node --version` must begin with `v24`. If `docker info` fails, start Docker Desktop,
|
|
19
|
+
Colima, or your usual Docker engine.
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
npm ci --ignore-scripts
|
|
28
|
-
npm run test:fixture
|
|
29
|
-
```
|
|
21
|
+
Choose the extra requirement for your project:
|
|
30
22
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
its labeled local runtime. It does not need a hosted Supabase project or credentials.
|
|
23
|
+
- **Supabase:** install Supabase CLI 2.117.0 and run `supabase --version`.
|
|
24
|
+
- **PostgreSQL:** download the local database image once:
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
```bash
|
|
27
|
+
docker pull postgres:17-alpine
|
|
28
|
+
```
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
30
|
+
Rehearsal will use that image with downloads disabled.
|
|
31
|
+
|
|
32
|
+
## 2. Install and open the guide
|
|
41
33
|
|
|
42
|
-
|
|
34
|
+
Run these commands from the directory containing your project's `package.json`:
|
|
43
35
|
|
|
44
36
|
```bash
|
|
45
|
-
|
|
37
|
+
npm install --save-dev @rehearsal-db/core@beta
|
|
38
|
+
npx rehearsal
|
|
46
39
|
```
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
Choose **Set the stage**, then choose Supabase or PostgreSQL. Rehearsal previews every file
|
|
42
|
+
before asking to create it. It will not replace an existing file.
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
project ID, application commands, and project-owned input paths. Do not run `doctor`
|
|
52
|
-
until the next section's files exist.
|
|
44
|
+
Review the generated `rehearsal.config.mjs`, especially:
|
|
53
45
|
|
|
54
|
-
|
|
46
|
+
- the migration directory;
|
|
47
|
+
- the application start and proof commands;
|
|
48
|
+
- the local ports.
|
|
55
49
|
|
|
56
|
-
|
|
50
|
+
The proof command should check behavior changed by the migration. A test that only checks
|
|
51
|
+
whether the home page loads is usually too weak.
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
- a sanitization policy describing every exported field;
|
|
60
|
-
- an active baseline below `.rehearsal/`;
|
|
61
|
-
- an application proof command that exits nonzero when the restored app is wrong.
|
|
62
|
-
|
|
63
|
-
For the generated default paths:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
mkdir -p infrastructure/rehearsal/supabase infrastructure/rehearsal rehearsal
|
|
67
|
-
cp supabase/config.toml infrastructure/rehearsal/supabase/config.toml
|
|
68
|
-
```
|
|
53
|
+
## 3. Prepare safe baseline inputs
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
not need. This must remain an unlinked local config; never run `supabase link` from it.
|
|
55
|
+
A **baseline** is the locked starting point restored before each rehearsal. Start with a
|
|
56
|
+
small synthetic dataset. Do not use raw production data.
|
|
73
57
|
|
|
74
|
-
|
|
75
|
-
`verification.commands` with real commands from your project. The proof should check a
|
|
76
|
-
restored relationship and the candidate schema—not merely that `/` returns 200.
|
|
58
|
+
Rehearsal needs:
|
|
77
59
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
60
|
+
| Input | What it contains |
|
|
61
|
+
| ------------------- | ---------------------------------------------------- |
|
|
62
|
+
| Records | Safe rows in NDJSON format: one JSON object per line |
|
|
63
|
+
| Migration ledger | The historical migrations represented by those rows |
|
|
64
|
+
| Sanitization policy | A decision for every included table and column |
|
|
65
|
+
| Storage manifest | Optional Supabase Storage files only |
|
|
81
66
|
|
|
82
|
-
|
|
67
|
+
A record looks like this:
|
|
83
68
|
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
id bigint generated by default as identity primary key,
|
|
87
|
-
name text not null,
|
|
88
|
-
created_at timestamptz not null default now()
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
insert into storage.buckets (id, name, public)
|
|
92
|
-
values ('fixture-assets', 'fixture-assets', false);
|
|
69
|
+
```json
|
|
70
|
+
{ "table": "widgets", "row": { "id": 1, "name": "Synthetic Widget" } }
|
|
93
71
|
```
|
|
94
72
|
|
|
95
|
-
|
|
73
|
+
Put your safe records and ledger inside the project. Conventional names such as
|
|
74
|
+
`rehearsal/sanitized-data.ndjson` and `rehearsal/migration-ledger.json` are discovered
|
|
75
|
+
automatically. The guide inspects their structure but does not print row values.
|
|
96
76
|
|
|
97
|
-
|
|
98
|
-
{
|
|
99
|
-
"policyVersion": 1,
|
|
100
|
-
"migrationCutoff": "20260101000000",
|
|
101
|
-
"tables": [
|
|
102
|
-
{
|
|
103
|
-
"name": "widgets",
|
|
104
|
-
"group": "synthetic",
|
|
105
|
-
"sourceRows": "STREAM AND SANITIZE",
|
|
106
|
-
"columns": [
|
|
107
|
-
{
|
|
108
|
-
"name": "id",
|
|
109
|
-
"action": "KEEP EXACTLY",
|
|
110
|
-
"generated": "NEVER",
|
|
111
|
-
"identity": "YES",
|
|
112
|
-
"foreignKey": null
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
"name": "name",
|
|
116
|
-
"action": "REPLACE WITH SYNTHETIC",
|
|
117
|
-
"generated": "NEVER",
|
|
118
|
-
"identity": "NO",
|
|
119
|
-
"foreignKey": null
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
"name": "created_at",
|
|
123
|
-
"action": "DERIVE",
|
|
124
|
-
"generated": "NEVER",
|
|
125
|
-
"identity": "NO",
|
|
126
|
-
"foreignKey": null
|
|
127
|
-
}
|
|
128
|
-
]
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
```
|
|
77
|
+
Follow the guide's recommended actions:
|
|
133
78
|
|
|
134
|
-
|
|
79
|
+
1. **Prepare the script** creates a draft sanitization policy.
|
|
80
|
+
2. **Review the script** asks you to classify every table and column.
|
|
81
|
+
3. **Create the baseline** validates and activates the reviewed inputs.
|
|
135
82
|
|
|
136
|
-
|
|
137
|
-
{
|
|
138
|
-
"table": "widgets",
|
|
139
|
-
"row": {
|
|
140
|
-
"id": 1,
|
|
141
|
-
"name": "Synthetic Widget",
|
|
142
|
-
"created_at": "2026-01-01T00:00:00.000Z"
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
83
|
+
Rehearsal will not activate a policy containing undecided fields.
|
|
146
84
|
|
|
147
|
-
|
|
85
|
+
The ledger must describe the exact historical SQL included in the baseline. Do not type
|
|
86
|
+
years of migration history by hand for a real project. Generate it through reviewed
|
|
87
|
+
project tooling. The [tutorial](tutorial.md) contains a complete synthetic example, and
|
|
88
|
+
[Baselines](baselines.md) explains the file formats.
|
|
148
89
|
|
|
149
|
-
|
|
150
|
-
[
|
|
151
|
-
{
|
|
152
|
-
"version": "20260101000000",
|
|
153
|
-
"name": "create_widgets",
|
|
154
|
-
"statements": [
|
|
155
|
-
"create table public.widgets (\n\tid bigint generated by default as identity primary key,\n\tname text not null,\n\tcreated_at timestamptz not null default now()\n)",
|
|
156
|
-
"insert into storage.buckets (id, name, public)\nvalues ('fixture-assets', 'fixture-assets', false)"
|
|
157
|
-
]
|
|
158
|
-
}
|
|
159
|
-
]
|
|
160
|
-
```
|
|
90
|
+
## 4. Reach READY
|
|
161
91
|
|
|
162
|
-
The
|
|
163
|
-
|
|
164
|
-
that is merely equivalent is rejected. For a production-shaped baseline, generate this
|
|
165
|
-
ledger through the project's reviewed source/export tooling; do not reconstruct years of
|
|
166
|
-
history by hand.
|
|
92
|
+
The guide displays four setup stages. Continue with its recommended action until all
|
|
93
|
+
checks are complete and the project reports `READY`.
|
|
167
94
|
|
|
168
|
-
|
|
95
|
+
You can run the same check directly:
|
|
169
96
|
|
|
170
97
|
```bash
|
|
171
|
-
npx rehearsal
|
|
172
|
-
--records=rehearsal/synthetic-data.ndjson \
|
|
173
|
-
--ledger=rehearsal/migration-ledger.json
|
|
98
|
+
npx rehearsal doctor
|
|
174
99
|
```
|
|
175
100
|
|
|
176
|
-
|
|
101
|
+
If it reports `NOT READY`, fix the listed item and run it again. Do not bypass a check or
|
|
102
|
+
add a hosted connection string.
|
|
177
103
|
|
|
178
|
-
|
|
104
|
+
## 5. Run the rehearsal
|
|
179
105
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
```
|
|
106
|
+
Choose **Run a rehearsal**. Rehearsal shows the exact candidate migrations and asks for
|
|
107
|
+
confirmation before it changes the disposable runtime.
|
|
183
108
|
|
|
184
|
-
|
|
109
|
+
A successful run:
|
|
185
110
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
111
|
+
1. restores the baseline;
|
|
112
|
+
2. applies only the migrations you approved;
|
|
113
|
+
3. verifies the local database;
|
|
114
|
+
4. launches the ordinary application when readiness is configured;
|
|
115
|
+
5. runs the ordinary test command and declared positive/negative HTTP proofs;
|
|
116
|
+
6. stops only the application process it launched.
|
|
117
|
+
|
|
118
|
+
Your original baseline remains unchanged.
|
|
189
119
|
|
|
190
|
-
|
|
191
|
-
|
|
120
|
+
If a source owner later approves a production-shaped copy, use the separate workflow in
|
|
121
|
+
[Optional production-shaped preparation](production-source.md). Do not add source
|
|
122
|
+
credentials to the normal config or runtime environment.
|
|
192
123
|
|
|
193
|
-
|
|
194
|
-
|
|
124
|
+
Once temporary source access is ready, `npx rehearsal refresh` previews the safe
|
|
125
|
+
replacement workflow. It means “get a newly verified copy.” By contrast, `reset` means
|
|
126
|
+
“discard local edits and restore the copy I already have.”
|
|
195
127
|
|
|
196
|
-
##
|
|
128
|
+
## 6. Use the sandbox and clean up
|
|
129
|
+
|
|
130
|
+
Choose **Open the sandbox app**, or run:
|
|
197
131
|
|
|
198
132
|
```bash
|
|
199
|
-
npx rehearsal
|
|
200
|
-
npx rehearsal candidates
|
|
201
|
-
npx rehearsal inspect baseline
|
|
202
|
-
npx rehearsal inspect migrations
|
|
133
|
+
npx rehearsal open
|
|
203
134
|
```
|
|
204
135
|
|
|
205
|
-
|
|
136
|
+
Open the local URL printed by Rehearsal. The app stays available for hands-on testing
|
|
137
|
+
until you press `Ctrl+C`. Only the app stops; your local database and Storage changes are
|
|
138
|
+
kept. Run `npx rehearsal open` again to continue where you left off.
|
|
206
139
|
|
|
207
|
-
|
|
140
|
+
Use the guide for normal runtime tasks:
|
|
208
141
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
142
|
+
- **Verify** checks the current runtime.
|
|
143
|
+
- **Reset** discards runtime edits and restores the baseline.
|
|
144
|
+
- **Stop** stops the runtime but keeps its local state.
|
|
145
|
+
- **Discard** removes this project's disposable runtime and volume.
|
|
146
|
+
|
|
147
|
+
Press `Ctrl+Z` at any prompt to exit the entire guide. It will not leave a suspended
|
|
148
|
+
process behind.
|
|
212
149
|
|
|
213
|
-
|
|
214
|
-
verifies the runtime, and runs the project-owned application proof. The resulting local
|
|
215
|
-
database is writable, so you can test real application changes without mutating the
|
|
216
|
-
baseline.
|
|
150
|
+
## Command-line setup
|
|
217
151
|
|
|
218
|
-
|
|
152
|
+
The guide is recommended for people. Scripts and CI can use explicit commands:
|
|
219
153
|
|
|
220
154
|
```bash
|
|
221
|
-
npx rehearsal
|
|
222
|
-
npx rehearsal
|
|
223
|
-
npx rehearsal
|
|
224
|
-
npx rehearsal
|
|
225
|
-
npx rehearsal stop
|
|
155
|
+
npx rehearsal setup --target=postgresql --write
|
|
156
|
+
npx rehearsal doctor
|
|
157
|
+
npx rehearsal candidates
|
|
158
|
+
npx rehearsal run --confirm-candidates=PASTE_DIGEST_HERE
|
|
226
159
|
```
|
|
227
160
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
stops only this project's runtime.
|
|
231
|
-
|
|
232
|
-
## Next steps
|
|
233
|
-
|
|
234
|
-
- Follow [the full tutorial](tutorial.md).
|
|
235
|
-
- Read [the security model](security-model.md) before designing a production export.
|
|
236
|
-
- Define an exhaustive [sanitization policy](sanitization.md).
|
|
237
|
-
- Learn the [baseline lifecycle](baselines.md).
|
|
161
|
+
Replace `postgresql` with `supabase` when needed. See [CLI commands](commands.md) for the
|
|
162
|
+
complete reference and [Troubleshooting](troubleshooting.md) when a check fails.
|
|
238
163
|
|
|
239
|
-
##
|
|
164
|
+
## Files Rehearsal creates
|
|
240
165
|
|
|
241
|
-
- `rehearsal.config.
|
|
242
|
-
- `.rehearsal
|
|
243
|
-
- `.rehearsal/
|
|
244
|
-
-
|
|
245
|
-
- `.rehearsal/runtime.env` contains generated loopback-only application credentials.
|
|
166
|
+
- `rehearsal.config.mjs` — reviewed project configuration
|
|
167
|
+
- `.rehearsal/` — ignored baselines, runtime files, and receipts
|
|
168
|
+
- `.rehearsal/runtime.env` — generated local-only application variables
|
|
169
|
+
- `infrastructure/rehearsal/supabase/config.toml` — Supabase-only local configuration
|
|
246
170
|
|
|
247
|
-
|
|
171
|
+
Keep `.rehearsal/` out of source control, even when its data is synthetic.
|
package/docs/glossary.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Glossary
|
|
1
|
+
# Glossary
|
|
2
2
|
|
|
3
3
|
**Baseline** — immutable sanitized starting artifact.
|
|
4
4
|
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
**Candidate digest** — checksum binding the exact candidate filenames and bytes.
|
|
8
8
|
|
|
9
|
+
**Dependent target** — another isolated local database managed with the primary runtime.
|
|
10
|
+
|
|
11
|
+
**Combined digest** — one checksum binding candidate or cleanup sets across every target.
|
|
12
|
+
|
|
9
13
|
**Project-owned** — application-specific policy or code that remains outside the package.
|
|
10
14
|
|
|
11
15
|
**Represented migration** — historical migration whose exact bytes are bound into the
|
|
@@ -19,13 +23,12 @@ baseline.
|
|
|
19
23
|
|
|
20
24
|
```mermaid
|
|
21
25
|
flowchart LR
|
|
22
|
-
A[
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
E --> F
|
|
27
|
-
F --> G[
|
|
28
|
-
G --> H[Verified local receipt]
|
|
26
|
+
A[Safe rows] --> B[Locked baseline]
|
|
27
|
+
C[Migration files] --> D[Reviewed plan]
|
|
28
|
+
B --> E[Disposable local database]
|
|
29
|
+
D --> E
|
|
30
|
+
E --> F[Application proof]
|
|
31
|
+
F --> G[Verified result]
|
|
29
32
|
```
|
|
30
33
|
|
|
31
34
|
The reusable package owns the path from a completed baseline plus migration directory to
|
|
@@ -1,33 +1,176 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
1.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
# Optional production-shaped preparation
|
|
2
|
+
|
|
3
|
+
Start with synthetic data. Use this workflow only when the source owner has approved the
|
|
4
|
+
exact tables, columns, owner scope, assets, and privacy policy.
|
|
5
|
+
|
|
6
|
+
Ordinary Rehearsal commands remain local-only. Source preparation is separate and cannot
|
|
7
|
+
be triggered by `run`, `reset`, `migrate`, `verify`, or application launch.
|
|
8
|
+
|
|
9
|
+
## 1. Add the config paths
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
preparation: {
|
|
13
|
+
sourcePolicy: "infrastructure/rehearsal/source-access-policy.json",
|
|
14
|
+
privacyKey: ".rehearsal/secrets/privacy.key",
|
|
15
|
+
batchRows: 500,
|
|
16
|
+
maximumRows: 1000000,
|
|
17
|
+
maximumBytes: 2147483648,
|
|
18
|
+
diskHeadroomBytes: 67108864,
|
|
19
|
+
},
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The privacy key stays ignored under `.rehearsal`. The policy is safe to review in source
|
|
23
|
+
control because it contains hashes and environment-variable names, not credentials,
|
|
24
|
+
URLs, or raw owner identifiers.
|
|
25
|
+
|
|
26
|
+
## 2. Declare the source boundary
|
|
27
|
+
|
|
28
|
+
`source-access-policy.json` uses this shape:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"accessVersion": 1,
|
|
33
|
+
"targetFingerprint": "<sha256 of the approved PostgreSQL host, port, and database>",
|
|
34
|
+
"administratorEnvironmentVariable": "REHEARSAL_SOURCE_ADMIN_URL",
|
|
35
|
+
"reader": {
|
|
36
|
+
"role": "rehearsal_example_reader",
|
|
37
|
+
"ownerRole": "rehearsal_example_owner",
|
|
38
|
+
"credentialFile": ".rehearsal/secrets/source-reader.env",
|
|
39
|
+
"validForMinutes": 30
|
|
40
|
+
},
|
|
41
|
+
"exportSchema": "rehearsal_export_example",
|
|
42
|
+
"migrationLedger": {
|
|
43
|
+
"schema": "supabase_migrations",
|
|
44
|
+
"table": "schema_migrations",
|
|
45
|
+
"versionColumn": "version",
|
|
46
|
+
"nameColumn": "name",
|
|
47
|
+
"statementsColumn": "statements"
|
|
48
|
+
},
|
|
49
|
+
"relations": [
|
|
50
|
+
{
|
|
51
|
+
"source": { "schema": "public", "table": "widgets" },
|
|
52
|
+
"view": "widgets",
|
|
53
|
+
"targetSchema": "public",
|
|
54
|
+
"targetTable": "widgets",
|
|
55
|
+
"columns": ["id", "owner_id", "name"],
|
|
56
|
+
"orderBy": ["id"],
|
|
57
|
+
"rowScope": { "kind": "approved-public" }
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"source": { "schema": "public", "table": "profiles" },
|
|
61
|
+
"view": "approved_owner_profile",
|
|
62
|
+
"targetSchema": "app_api",
|
|
63
|
+
"targetTable": "profiles",
|
|
64
|
+
"columns": ["id", "email"],
|
|
65
|
+
"orderBy": ["id"],
|
|
66
|
+
"rowScope": {
|
|
67
|
+
"kind": "approved-owner",
|
|
68
|
+
"column": "id",
|
|
69
|
+
"valueEnvironmentVariable": "REHEARSAL_APPROVED_OWNER_ID"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"assets": []
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Calculate fingerprints with the exported helpers from `@rehearsal-db/core/source-access`
|
|
78
|
+
or a reviewed local script. A fingerprint binds the destination without recording its
|
|
79
|
+
address. Changing the host, port, or database invalidates the plan.
|
|
80
|
+
|
|
81
|
+
`approved-public` means every selected row is licensed or otherwise approved for this
|
|
82
|
+
use. `approved-owner` requires one explicit owner value from the named environment
|
|
83
|
+
variable. Rehearsal never chooses an owner by finding an administrator.
|
|
84
|
+
|
|
85
|
+
`targetSchema` is optional and defaults to `public`. Set it when the restored relation
|
|
86
|
+
belongs elsewhere, and use the same schema in privacy policy version 2. This is relation
|
|
87
|
+
identity, not a request to search every schema.
|
|
88
|
+
|
|
89
|
+
For Storage, add an `assetReader` block and approved `assets` entries. The reader URL and
|
|
90
|
+
token come from named environment variables. Objects outside the exact bucket/prefix are
|
|
91
|
+
not listed or downloaded. Size, object-count, path, ETag, and exact-byte checks apply.
|
|
92
|
+
|
|
93
|
+
## 3. Use executable privacy policy version 2
|
|
94
|
+
|
|
95
|
+
Every selected column has one action and, where required, a bounded recipe:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"policyVersion": 2,
|
|
100
|
+
"migrationCutoff": "20260101000000",
|
|
101
|
+
"tables": [
|
|
102
|
+
{
|
|
103
|
+
"schema": "app_api",
|
|
104
|
+
"name": "profiles",
|
|
105
|
+
"sourceRows": "STREAM AND SANITIZE",
|
|
106
|
+
"columns": [
|
|
107
|
+
{
|
|
108
|
+
"name": "id",
|
|
109
|
+
"action": "PSEUDONYMIZE",
|
|
110
|
+
"recipe": { "format": "uuid", "namespace": "account-id" },
|
|
111
|
+
"generated": "NEVER",
|
|
112
|
+
"identity": "NO",
|
|
113
|
+
"foreignKey": null
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "email",
|
|
117
|
+
"action": "PSEUDONYMIZE",
|
|
118
|
+
"recipe": { "format": "email", "namespace": "account-email" },
|
|
119
|
+
"generated": "NEVER",
|
|
120
|
+
"identity": "NO",
|
|
121
|
+
"foreignKey": null
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Supported recipes are intentionally small: keyed UUID/email/text/integer pseudonyms,
|
|
130
|
+
explicit constants, bounded date shifts, and fully classified JSON objects. Unknown
|
|
131
|
+
tables, columns, JSON keys, formats, and recipes stop the refresh. There is no JavaScript
|
|
132
|
+
or SQL escape hatch.
|
|
133
|
+
|
|
134
|
+
## 4. Preview, apply, refresh, and retire
|
|
135
|
+
|
|
136
|
+
Keep credentials out of shell history by loading them from an owner-only environment
|
|
137
|
+
manager or file, then run:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx rehearsal privacy key --write
|
|
141
|
+
npx rehearsal source plan
|
|
142
|
+
npx rehearsal source apply --confirm-source-access=<full-sha256>
|
|
143
|
+
npx rehearsal refresh
|
|
144
|
+
npx rehearsal refresh --confirm-refresh=<full-sha256>
|
|
145
|
+
npx rehearsal source retire
|
|
146
|
+
npx rehearsal source retire --confirm-source-retirement=<full-sha256>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`source apply` creates new time-limited roles and export views only when every exact name
|
|
150
|
+
is unused. It verifies the reader cannot read raw tables, write, escalate roles, or call
|
|
151
|
+
an exposed security-definer network function. Externally provisioned readers are not yet
|
|
152
|
+
supported; use the managed reader so Rehearsal can prove its scope and retirement.
|
|
153
|
+
|
|
154
|
+
`refresh` previews the complete replacement first. After exact confirmation, its baseline
|
|
155
|
+
step uses one read-only repeatable-read transaction for the schema shape,
|
|
156
|
+
migration ledger, and rows. It streams in bounded batches, records only counts and
|
|
157
|
+
hashes, stages privately, rechecks schema/ledger drift, and activates atomically. It then
|
|
158
|
+
resets the local runtime stack and applies configured baseline retention. A failed new
|
|
159
|
+
runtime is rolled back to the previous baseline and runtime. The lower-level `baseline
|
|
160
|
+
refresh` command remains available when automation should activate a baseline without
|
|
161
|
+
resetting the runtime or pruning old generations.
|
|
162
|
+
|
|
163
|
+
Storage cannot share PostgreSQL's transaction snapshot. Rehearsal instead verifies each
|
|
164
|
+
object's inventory version and byte count during transfer, then records its SHA-256 in
|
|
165
|
+
the immutable baseline.
|
|
166
|
+
|
|
167
|
+
`source retire` inventories the exact recorded views before removal, then removes only
|
|
168
|
+
those views, the two recorded roles, and local credential/receipt files. Unrelated roles,
|
|
169
|
+
grants, objects, baselines, runtimes, and Docker resources are preserved.
|
|
170
|
+
|
|
171
|
+
## Limits
|
|
172
|
+
|
|
173
|
+
Rehearsal does not decide consent, licensing, retention rights, privileged-role meaning,
|
|
174
|
+
or which owner is yours. It does not provide an OS firewall, backup, disaster recovery,
|
|
175
|
+
or universal database support. Real Google account selection and provider callbacks
|
|
176
|
+
still require direct human observation; a synthetic redirect cannot prove them.
|