@rehearsal-db/core 0.1.0-beta.1 → 0.1.0-beta.11
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 +271 -1
- package/COMPATIBILITY.md +26 -0
- package/README.md +150 -346
- package/SECURITY.md +2 -1
- package/SUPPORT.md +5 -0
- package/docs/README.md +38 -0
- package/docs/adapters.md +20 -6
- package/docs/architecture.md +58 -0
- package/docs/baselines.md +102 -22
- package/docs/commands.md +202 -33
- package/docs/configuration.md +288 -13
- package/docs/getting-started.md +114 -181
- package/docs/glossary.md +11 -8
- package/docs/index.md +47 -0
- package/docs/production-source.md +176 -33
- package/docs/releasing.md +28 -38
- package/docs/roadmap.md +41 -0
- package/docs/runtime-policies.md +253 -0
- package/docs/sanitization.md +144 -8
- package/docs/security-model.md +34 -9
- package/docs/standalone-workflow.md +109 -0
- package/docs/troubleshooting.md +127 -2
- package/docs/tutorial.md +70 -59
- package/package.json +39 -23
- package/scripts/install/create_root_config.mjs +36 -0
- 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 +741 -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/init_command.mjs +77 -0
- package/src/cli/rehearsal.mjs +952 -0
- package/src/cli/renderers.mjs +589 -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 +1163 -0
- package/src/identity/storage.mjs +165 -0
- package/{scripts/lib/rehearsal → src/project}/configuration.d.mts +72 -4
- package/src/project/configuration.mjs +1201 -0
- package/src/project/install_scaffold.mjs +291 -0
- package/src/project/setup.mjs +484 -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,180 @@
|
|
|
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
|
+
With npm, a normal application install creates `rehearsal.config.mjs`, the dedicated
|
|
42
|
+
local runtime config, and the required `.gitignore` entries when Rehearsal can prove the
|
|
43
|
+
application root. It never replaces an existing file. Review the generated config,
|
|
44
|
+
especially:
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
- the migration directory;
|
|
47
|
+
- the application start and proof commands;
|
|
48
|
+
- the local ports.
|
|
53
49
|
|
|
54
|
-
|
|
50
|
+
If lifecycle scripts were disabled, a global/cache install was used, or a workspace has
|
|
51
|
+
more than one possible application, no project files are created automatically. Run
|
|
52
|
+
`npx rehearsal` inside the intended application, choose **Set the stage**, select
|
|
53
|
+
Supabase or PostgreSQL, and approve the same safe setup preview.
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
The proof command should check behavior changed by the migration. A test that only checks
|
|
56
|
+
whether the home page loads is usually too weak.
|
|
57
57
|
|
|
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
|
-
```
|
|
58
|
+
## 3. Prepare safe baseline inputs
|
|
69
59
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
not need. This must remain an unlinked local config; never run `supabase link` from it.
|
|
60
|
+
A **baseline** is the locked starting point restored before each rehearsal. Start with a
|
|
61
|
+
small synthetic dataset. Do not use raw production data.
|
|
73
62
|
|
|
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.
|
|
63
|
+
Rehearsal needs:
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
| Input | What it contains |
|
|
66
|
+
| ------------------- | ---------------------------------------------------- |
|
|
67
|
+
| Records | Safe rows in NDJSON format: one JSON object per line |
|
|
68
|
+
| Migration ledger | The historical migrations represented by those rows |
|
|
69
|
+
| Sanitization policy | A decision for every included table and column |
|
|
70
|
+
| Storage manifest | Optional Supabase Storage files only |
|
|
81
71
|
|
|
82
|
-
|
|
72
|
+
A record looks like this:
|
|
83
73
|
|
|
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);
|
|
74
|
+
```json
|
|
75
|
+
{ "table": "widgets", "row": { "id": 1, "name": "Synthetic Widget" } }
|
|
93
76
|
```
|
|
94
77
|
|
|
95
|
-
|
|
78
|
+
Put your safe records and ledger inside the project. Conventional names such as
|
|
79
|
+
`rehearsal/sanitized-data.ndjson` and `rehearsal/migration-ledger.json` are discovered
|
|
80
|
+
automatically. The guide inspects their structure but does not print row values.
|
|
96
81
|
|
|
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
|
-
```
|
|
82
|
+
Follow the guide's recommended actions:
|
|
133
83
|
|
|
134
|
-
|
|
84
|
+
1. **Prepare the script** creates a draft sanitization policy.
|
|
85
|
+
2. **Review the script** asks you to classify every table and column.
|
|
86
|
+
3. **Create the baseline** validates and activates the reviewed inputs.
|
|
135
87
|
|
|
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
|
-
```
|
|
88
|
+
Rehearsal will not activate a policy containing undecided fields.
|
|
146
89
|
|
|
147
|
-
|
|
90
|
+
The ledger must describe the exact historical SQL included in the baseline. Do not type
|
|
91
|
+
years of migration history by hand for a real project. Generate it through reviewed
|
|
92
|
+
project tooling. The [tutorial](tutorial.md) contains a complete synthetic example, and
|
|
93
|
+
[Baselines](baselines.md) explains the file formats.
|
|
148
94
|
|
|
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
|
-
```
|
|
95
|
+
## 4. Reach READY
|
|
161
96
|
|
|
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.
|
|
97
|
+
The guide displays four setup stages. Continue with its recommended action until all
|
|
98
|
+
checks are complete and the project reports `READY`.
|
|
167
99
|
|
|
168
|
-
|
|
100
|
+
You can run the same check directly:
|
|
169
101
|
|
|
170
102
|
```bash
|
|
171
|
-
npx rehearsal
|
|
172
|
-
--records=rehearsal/synthetic-data.ndjson \
|
|
173
|
-
--ledger=rehearsal/migration-ledger.json
|
|
103
|
+
npx rehearsal doctor
|
|
174
104
|
```
|
|
175
105
|
|
|
176
|
-
|
|
106
|
+
If it reports `NOT READY`, fix the listed item and run it again. Do not bypass a check or
|
|
107
|
+
add a hosted connection string.
|
|
177
108
|
|
|
178
|
-
|
|
109
|
+
## 5. Run the rehearsal
|
|
179
110
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
```
|
|
111
|
+
Choose **Run a rehearsal**. Rehearsal shows the exact candidate migrations and asks for
|
|
112
|
+
confirmation before it changes the disposable runtime.
|
|
183
113
|
|
|
184
|
-
|
|
114
|
+
A successful run:
|
|
185
115
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
116
|
+
1. restores the baseline;
|
|
117
|
+
2. applies only the migrations you approved;
|
|
118
|
+
3. verifies the local database;
|
|
119
|
+
4. launches the ordinary application when readiness is configured;
|
|
120
|
+
5. runs the ordinary test command and declared positive/negative HTTP proofs;
|
|
121
|
+
6. stops only the application process it launched.
|
|
122
|
+
|
|
123
|
+
Your original baseline remains unchanged.
|
|
124
|
+
|
|
125
|
+
If a source owner later approves a production-shaped copy, use the separate workflow in
|
|
126
|
+
[Optional production-shaped preparation](production-source.md). Do not add source
|
|
127
|
+
credentials to the normal config or runtime environment.
|
|
189
128
|
|
|
190
|
-
|
|
191
|
-
|
|
129
|
+
Once temporary source access is ready, `npx rehearsal refresh` previews the safe
|
|
130
|
+
replacement workflow. It means “get a newly verified copy.” By contrast, `reset` means
|
|
131
|
+
“discard local edits and restore the copy I already have.”
|
|
192
132
|
|
|
193
|
-
|
|
194
|
-
check or copy a hosted connection string into the generated runtime environment.
|
|
133
|
+
## 6. Use the sandbox and clean up
|
|
195
134
|
|
|
196
|
-
|
|
135
|
+
Choose **Open the sandbox app**, or run:
|
|
197
136
|
|
|
198
137
|
```bash
|
|
199
|
-
npx rehearsal
|
|
200
|
-
npx rehearsal candidates
|
|
201
|
-
npx rehearsal inspect baseline
|
|
202
|
-
npx rehearsal inspect migrations
|
|
138
|
+
npx rehearsal open
|
|
203
139
|
```
|
|
204
140
|
|
|
205
|
-
|
|
141
|
+
Open the local URL printed by Rehearsal. The app stays available for hands-on testing
|
|
142
|
+
until you press `Ctrl+C`. Only the app stops; your local database and Storage changes are
|
|
143
|
+
kept. Run `npx rehearsal open` again to continue where you left off.
|
|
206
144
|
|
|
207
|
-
|
|
145
|
+
Use the guide for normal runtime tasks:
|
|
208
146
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
147
|
+
- **Verify** checks the current runtime.
|
|
148
|
+
- **Reset** discards runtime edits and restores the baseline.
|
|
149
|
+
- **Stop** stops the runtime but keeps its local state.
|
|
150
|
+
- **Discard** removes this project's disposable runtime and volume.
|
|
212
151
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
database is writable, so you can test real application changes without mutating the
|
|
216
|
-
baseline.
|
|
152
|
+
Press `Ctrl+Z` at any prompt to exit the entire guide. It will not leave a suspended
|
|
153
|
+
process behind.
|
|
217
154
|
|
|
218
|
-
##
|
|
155
|
+
## Command-line setup
|
|
156
|
+
|
|
157
|
+
The guide is recommended for people. Scripts and CI can use explicit commands:
|
|
219
158
|
|
|
220
159
|
```bash
|
|
221
|
-
npx rehearsal
|
|
222
|
-
npx rehearsal
|
|
223
|
-
npx rehearsal
|
|
224
|
-
npx rehearsal
|
|
225
|
-
npx rehearsal stop
|
|
160
|
+
npx rehearsal setup --target=postgresql --write
|
|
161
|
+
npx rehearsal doctor
|
|
162
|
+
npx rehearsal candidates
|
|
163
|
+
npx rehearsal run --confirm-candidates=PASTE_DIGEST_HERE
|
|
226
164
|
```
|
|
227
165
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
stops only this project's runtime.
|
|
231
|
-
|
|
232
|
-
## Next steps
|
|
166
|
+
Replace `postgresql` with `supabase` when needed. See [CLI commands](commands.md) for the
|
|
167
|
+
complete reference and [Troubleshooting](troubleshooting.md) when a check fails.
|
|
233
168
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
- Learn the [baseline lifecycle](baselines.md).
|
|
169
|
+
Running setup again is safe: existing configuration and runtime files are reported as
|
|
170
|
+
unchanged. Rehearsal only adds missing ignore entries. It never refreshes an existing
|
|
171
|
+
config during an upgrade.
|
|
238
172
|
|
|
239
|
-
##
|
|
173
|
+
## Files Rehearsal creates
|
|
240
174
|
|
|
241
|
-
- `rehearsal.config.
|
|
242
|
-
- `.rehearsal
|
|
243
|
-
- `.rehearsal/
|
|
244
|
-
-
|
|
245
|
-
- `.rehearsal/runtime.env` contains generated loopback-only application credentials.
|
|
175
|
+
- `rehearsal.config.mjs` — reviewed project configuration
|
|
176
|
+
- `.rehearsal/` — ignored baselines, runtime files, and receipts
|
|
177
|
+
- `.rehearsal/runtime.env` — generated local-only application variables
|
|
178
|
+
- `infrastructure/rehearsal/supabase/config.toml` — Supabase-only local configuration
|
|
246
179
|
|
|
247
|
-
|
|
180
|
+
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
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Rehearsal documentation
|
|
2
|
+
|
|
3
|
+
## Pick the path that fits today
|
|
4
|
+
|
|
5
|
+
You do not need to read everything before your first rehearsal. Start with the outcome
|
|
6
|
+
you want, then follow the links when a term or safety check is new.
|
|
7
|
+
|
|
8
|
+
| I want to… | Go here |
|
|
9
|
+
| ------------------------------------- | ----------------------------------------------------------------- |
|
|
10
|
+
| Set up my own project | [Getting started](getting-started.md) |
|
|
11
|
+
| Try Rehearsal without touching my app | [Hands-on tutorial](tutorial.md) |
|
|
12
|
+
| Understand what makes a copy safe | [Baselines](baselines.md) and [Sanitization](sanitization.md) |
|
|
13
|
+
| Look up a command or setting | [CLI commands](commands.md) and [Configuration](configuration.md) |
|
|
14
|
+
| Fix something that did not work | [Troubleshooting](troubleshooting.md) |
|
|
15
|
+
|
|
16
|
+
## The short version
|
|
17
|
+
|
|
18
|
+
Rehearsal restores an approved local baseline, applies only the migration files you
|
|
19
|
+
reviewed, and runs the application checks your project owns. The normal workflow stays
|
|
20
|
+
on your computer and does not deploy anything.
|
|
21
|
+
|
|
22
|
+
1. **Prepare** a safe baseline.
|
|
23
|
+
2. **Review** the exact candidate migrations.
|
|
24
|
+
3. **Run** them in a disposable local database.
|
|
25
|
+
4. **Prove** the application behavior that matters.
|
|
26
|
+
5. **Open** the sandbox for hands-on testing.
|
|
27
|
+
|
|
28
|
+
## Safety is part of the workflow
|
|
29
|
+
|
|
30
|
+
Rehearsal does not ask you to trust one giant switch. Baseline checksums, local-only
|
|
31
|
+
networking, exact confirmation digests, project-owned proofs, and narrowly owned cleanup
|
|
32
|
+
each protect a different boundary.
|
|
33
|
+
|
|
34
|
+
Start with synthetic data when you can. If a project needs a production-shaped copy,
|
|
35
|
+
read [Production-shaped preparation](production-source.md) before providing any source
|
|
36
|
+
access.
|
|
37
|
+
|
|
38
|
+
## Still unsure where to begin?
|
|
39
|
+
|
|
40
|
+
Run the interactive guide from the project you want to test:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx rehearsal
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
It reads the project state, explains the next safe step, and keeps the full command
|
|
47
|
+
reference available when you need it.
|
|
@@ -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.
|