@rehearsal-db/core 0.1.0-beta.1

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 (35) hide show
  1. package/BENCHMARKS.md +61 -0
  2. package/CHANGELOG.md +59 -0
  3. package/COMPATIBILITY.md +22 -0
  4. package/LICENSE +21 -0
  5. package/README.md +375 -0
  6. package/SECURITY.md +19 -0
  7. package/SUPPORT.md +15 -0
  8. package/docs/adapters.md +23 -0
  9. package/docs/baselines.md +33 -0
  10. package/docs/commands.md +35 -0
  11. package/docs/configuration.md +98 -0
  12. package/docs/getting-started.md +247 -0
  13. package/docs/glossary.md +33 -0
  14. package/docs/production-source.md +33 -0
  15. package/docs/releasing.md +79 -0
  16. package/docs/sanitization.md +69 -0
  17. package/docs/security-model.md +40 -0
  18. package/docs/troubleshooting.md +50 -0
  19. package/docs/tutorial.md +96 -0
  20. package/package.json +77 -0
  21. package/scripts/lib/environment/local_supabase.mjs +197 -0
  22. package/scripts/lib/rehearsal/baseline_artifact.mjs +536 -0
  23. package/scripts/lib/rehearsal/baseline_builder.mjs +155 -0
  24. package/scripts/lib/rehearsal/configuration.d.mts +85 -0
  25. package/scripts/lib/rehearsal/configuration.mjs +559 -0
  26. package/scripts/lib/rehearsal/diagnostics.mjs +193 -0
  27. package/scripts/lib/rehearsal/migration_history.mjs +220 -0
  28. package/scripts/lib/rehearsal/plan.mjs +587 -0
  29. package/scripts/lib/rehearsal/process_environment.mjs +64 -0
  30. package/scripts/lib/rehearsal/runtime_restore.mjs +310 -0
  31. package/scripts/lib/rehearsal/sanitization_policy.mjs +169 -0
  32. package/scripts/lib/rehearsal/schema_snapshot.mjs +113 -0
  33. package/scripts/lib/rehearsal/service_environment.mjs +82 -0
  34. package/scripts/operations/database/manage_rehearsal_database.mjs +784 -0
  35. package/scripts/operations/rehearsal/rehearsal_cli.mjs +565 -0
@@ -0,0 +1,35 @@
1
+ # CLI commands
2
+
3
+ All commands run from the consuming project root. State-reporting commands accept
4
+ `--json`; `--verbose` and `--debug` increase safe diagnostics without revealing row
5
+ values or credentials.
6
+
7
+ | Command | Mutates local state | Purpose |
8
+ | ------------------------------------------------------------ | ------------------- | --------------------------------------------------------- |
9
+ | `rehearsal init` | No | Preview safe starter configuration. |
10
+ | `rehearsal init --write` | Config only | Create config without overwriting. |
11
+ | `rehearsal baseline create --records=<path> --ledger=<path>` | Artifact only | Activate a baseline from explicit safe local inputs. |
12
+ | `rehearsal doctor` | No | Check dependencies, inputs, and safety barriers. |
13
+ | `rehearsal explain` | No | Print the immutable execution plan. |
14
+ | `rehearsal run --dry-run` | No | Alias the same plan used by `explain`. |
15
+ | `rehearsal candidates` | No | Print pending migrations and their exact digest. |
16
+ | `rehearsal inspect baseline` | No | Print data-free artifact provenance. |
17
+ | `rehearsal inspect migrations` | No | Classify each migration. |
18
+ | `rehearsal run --confirm-candidates=<sha256>` | Yes, local only | Reset, apply exact candidates, verify, and run app proof. |
19
+ | `rehearsal start` | Runtime only | Start a verified runtime without resetting its data. |
20
+ | `rehearsal migrate --confirm-candidates=<sha256>` | Yes, local only | Apply the exact suffix without resetting current data. |
21
+ | `rehearsal verify` | No data mutation | Verify the current local runtime and receipt. |
22
+ | `rehearsal status` | No | Report runtime, baseline, and candidate state. |
23
+ | `rehearsal reset` | Yes, local only | Replace runtime data with the immutable baseline. |
24
+ | `rehearsal stop` | Runtime only | Stop this project's local services. |
25
+ | `rehearsal discard` | Yes, local only | Remove only this project's disposable runtime and volume. |
26
+
27
+ `run` requires the digest from the current candidate set. Any added, removed, reordered,
28
+ or edited migration changes the digest and invalidates the confirmation.
29
+
30
+ `baseline create` never extracts data. The NDJSON and migration-ledger files must already
31
+ exist inside the project and be safe to retain. Add `--assets=<manifest.json>` to include
32
+ bounded local Storage bytes; every manifest `file` must also remain inside the project.
33
+
34
+ Automation should use `--json` and inspect both exit status and the versioned envelope.
35
+ Exit-code meanings are documented in the root README. Scripts must not parse human text.
@@ -0,0 +1,98 @@
1
+ # Configuration reference
2
+
3
+ `rehearsal.config.ts` is executable configuration with a strict versioned schema.
4
+ Unknown fields and unknown schema versions are errors, not warnings.
5
+
6
+ ```ts
7
+ import { defineRehearsalConfig } from "@rehearsal-db/core";
8
+
9
+ export default defineRehearsalConfig({
10
+ schemaVersion: 1,
11
+ project: { name: "example-app" },
12
+ supabase: {
13
+ workdir: ".",
14
+ migrationDirectory: "supabase/migrations",
15
+ rehearsalConfig: "infrastructure/rehearsal/supabase/config.toml",
16
+ runtimeWorkdir: ".rehearsal/runtime",
17
+ },
18
+ baseline: {
19
+ artifactDirectory: ".rehearsal",
20
+ sanitizationPolicy: "infrastructure/rehearsal/sanitization-policy.json",
21
+ },
22
+ application: {
23
+ startCommand: "npm run dev:rehearsal",
24
+ proofCommand: "npm run test:rehearsal",
25
+ },
26
+ runtime: {
27
+ applicationUrl: "http://localhost:5175",
28
+ projectId: "example-app-rehearsal",
29
+ apiPort: 58321,
30
+ databasePort: 58322,
31
+ studioPort: 58323,
32
+ },
33
+ safety: { hostedAccess: "disabled", outboundNetwork: "deny" },
34
+ });
35
+ ```
36
+
37
+ ## Paths
38
+
39
+ All paths resolve inside the consuming project. The artifact directory must be named
40
+ `.rehearsal`; this is an intentional deletion guard. `runtimeWorkdir` must be its
41
+ `runtime` child, and the generated application environment file must remain inside it.
42
+
43
+ ## Supabase service environment
44
+
45
+ Some local identity providers need a client ID and secret. Configure both fields or
46
+ neither:
47
+
48
+ ```ts
49
+ serviceEnvironmentFile: ".env.rehearsal-service.local",
50
+ serviceEnvironmentVariables: ["LOCAL_IDP_CLIENT_ID", "LOCAL_IDP_SECRET"],
51
+ ```
52
+
53
+ The file must be ignored, owner-readable only, and contain only the exact allowlisted
54
+ names. These credentials may authorize an identity handshake, but the callback must
55
+ terminate at local Auth. They do not grant hosted database access.
56
+
57
+ ## Safety fields
58
+
59
+ Version 1 accepts loopback hosts only. `hostedAccess` can only be `disabled`, and
60
+ `outboundNetwork` can only be `deny`. Ambient hosted Supabase variables are quarantined
61
+ from child processes. There is no force flag to weaken these rules.
62
+
63
+ ## Ports and project identity
64
+
65
+ Use unique, non-privileged ports that do not overlap. `projectId` accepts lowercase
66
+ letters, numbers, and hyphens. It labels the local Docker resources so cleanup targets
67
+ only this project.
68
+
69
+ ## Application proof
70
+
71
+ `proofCommand` is mandatory and project-owned. It should test restored relationships,
72
+ authentication shape, critical reads, and candidate-migration behavior. A command that
73
+ only checks whether the home page returns 200 is usually too weak.
74
+
75
+ ## Runtime adapters
76
+
77
+ Most projects do not need an adapter. Use one only for schema-specific restore setup,
78
+ synthetic local identities, explicit generated environment variables, or post-restore
79
+ invariants. See [adapters](adapters.md).
80
+
81
+ ## Advanced library entry points
82
+
83
+ The CLI is the primary interface. Baseline builders and project-owned refresh tooling
84
+ may use these explicit subpaths:
85
+
86
+ - `@rehearsal-db/core/baseline`
87
+ - `@rehearsal-db/core/migrations`
88
+ - `@rehearsal-db/core/schema`
89
+ - `@rehearsal-db/core/diagnostics`
90
+ - `@rehearsal-db/core/process-environment`
91
+ - `@rehearsal-db/core/service-environment`
92
+
93
+ These advanced entry points are ESM JavaScript APIs in the first beta. The root
94
+ configuration and sanitization API has TypeScript declarations; the advanced subpaths do
95
+ not yet promise a typed surface.
96
+
97
+ Undocumented files under `scripts/` are package internals and are not compatibility
98
+ contracts.
@@ -0,0 +1,247 @@
1
+ # Getting started
2
+
3
+ This guide creates a safe local Rehearsal project from synthetic data. It does not
4
+ connect to production, request hosted credentials, or require an existing baseline.
5
+
6
+ ## Prerequisites
7
+
8
+ - Node.js 24
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
13
+
14
+ Confirm the tools first:
15
+
16
+ ```bash
17
+ node --version
18
+ npm --version
19
+ supabase --version
20
+ docker info
21
+ ```
22
+
23
+ If you want to see the complete lifecycle before touching your own project, clone the
24
+ Rehearsal repository and run:
25
+
26
+ ```bash
27
+ npm ci --ignore-scripts
28
+ npm run test:fixture
29
+ ```
30
+
31
+ That proof installs the packed package into a disposable fictional project, restores a
32
+ row and Storage object, applies a valid migration, rejects invalid SQL, and removes only
33
+ its labeled local runtime. It does not need a hosted Supabase project or credentials.
34
+
35
+ ## 1. Install and initialize
36
+
37
+ ```bash
38
+ npm install --save-dev @rehearsal-db/core
39
+ npx rehearsal init
40
+ ```
41
+
42
+ `init` is a preview. Read the generated configuration, then explicitly write it:
43
+
44
+ ```bash
45
+ npx rehearsal init --write
46
+ ```
47
+
48
+ Rehearsal never overwrites an existing configuration.
49
+
50
+ The generated configuration is intentionally incomplete until you review its ports,
51
+ project ID, application commands, and project-owned input paths. Do not run `doctor`
52
+ until the next section's files exist.
53
+
54
+ ## 2. Add the project-owned inputs
55
+
56
+ Create the paths named by `rehearsal.config.ts`:
57
+
58
+ - a dedicated local Supabase `config.toml`;
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
+ ```
69
+
70
+ Edit the copied Supabase config. Give it the same unique `project_id`, API port, database
71
+ port, and Studio port used by `rehearsal.config.ts`. Disable services your proof does
72
+ not need. This must remain an unlinked local config; never run `supabase link` from it.
73
+
74
+ Also replace the generated `application.startCommand`, `application.proofCommand`, and
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.
77
+
78
+ Start with synthetic rows shaped like your schema. Do not start onboarding with
79
+ production data. The following SQL, policy, row, and ledger form one matched example;
80
+ do not mix them with differently shaped snippets.
81
+
82
+ Historical migration `supabase/migrations/20260101000000_create_widgets.sql`:
83
+
84
+ ```sql
85
+ create table public.widgets (
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);
93
+ ```
94
+
95
+ Sanitization policy `infrastructure/rehearsal/sanitization-policy.json`:
96
+
97
+ ```json
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
+ ```
133
+
134
+ Safe row `rehearsal/synthetic-data.ndjson` (one JSON object per physical line):
135
+
136
+ ```json
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
+ ```
146
+
147
+ Migration ledger `rehearsal/migration-ledger.json`:
148
+
149
+ ```json
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
+ ```
161
+
162
+ The ledger is evidence, not a second migration language. Its version, name, order, and
163
+ statements must exactly represent the historical migration bytes in the baseline. SQL
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.
167
+
168
+ Then activate the safe input:
169
+
170
+ ```bash
171
+ npx rehearsal baseline create \
172
+ --records=rehearsal/synthetic-data.ndjson \
173
+ --ledger=rehearsal/migration-ledger.json
174
+ ```
175
+
176
+ The independent fixture in this repository is the executable reference example.
177
+
178
+ Expected result:
179
+
180
+ ```text
181
+ Activated synthetic baseline ...: 1 rows across 1 tables; 1 migrations through 20260101000000.
182
+ ```
183
+
184
+ ## 3. Check readiness
185
+
186
+ ```bash
187
+ npx rehearsal doctor
188
+ ```
189
+
190
+ Do not continue until it ends with `READY`. Doctor checks the local-only boundary,
191
+ dependencies, artifact integrity, migration lineage, ports, and project commands.
192
+
193
+ If it reports `NOT READY`, fix each named prerequisite and rerun it. Do not bypass a
194
+ check or copy a hosted connection string into the generated runtime environment.
195
+
196
+ ## 4. Review pending work
197
+
198
+ ```bash
199
+ npx rehearsal explain
200
+ npx rehearsal candidates
201
+ npx rehearsal inspect baseline
202
+ npx rehearsal inspect migrations
203
+ ```
204
+
205
+ The plan prints an exact candidate digest. It does not start services or change data.
206
+
207
+ ## 5. Run the rehearsal
208
+
209
+ ```bash
210
+ npx rehearsal run --confirm-candidates=<sha256>
211
+ ```
212
+
213
+ Rehearsal restores the immutable baseline, applies only the confirmed migration suffix,
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.
217
+
218
+ ## 6. Work, verify, and reset
219
+
220
+ ```bash
221
+ npx rehearsal status
222
+ npx rehearsal start
223
+ npx rehearsal verify
224
+ npx rehearsal reset
225
+ npx rehearsal stop
226
+ ```
227
+
228
+ Changes persist in the disposable runtime until `reset` or runtime removal. `start`
229
+ resumes that runtime without resetting it. `reset` restores the exact baseline. `stop`
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).
238
+
239
+ ## Generated files
240
+
241
+ - `rehearsal.config.ts` is written only by `init --write`.
242
+ - `.rehearsal/generations/<id>/` contains one immutable baseline generation.
243
+ - `.rehearsal/current` selects the active generation atomically.
244
+ - `.rehearsal/runtime/` contains the disposable local Supabase project and receipts.
245
+ - `.rehearsal/runtime.env` contains generated loopback-only application credentials.
246
+
247
+ Ignore all of `.rehearsal/`. Do not commit it even when its inputs were synthetic.
@@ -0,0 +1,33 @@
1
+ # Glossary and architecture
2
+
3
+ **Baseline** — immutable sanitized starting artifact.
4
+
5
+ **Candidate migration** — ordered migration suffix not represented by the baseline.
6
+
7
+ **Candidate digest** — checksum binding the exact candidate filenames and bytes.
8
+
9
+ **Project-owned** — application-specific policy or code that remains outside the package.
10
+
11
+ **Represented migration** — historical migration whose exact bytes are bound into the
12
+ baseline.
13
+
14
+ **Runtime** — disposable, writable local Supabase/PostgreSQL environment.
15
+
16
+ **Sanitization policy** — exhaustive project decision for every exported field.
17
+
18
+ **Verified receipt** — local evidence that the exact runtime and candidate suffix passed.
19
+
20
+ ```mermaid
21
+ flowchart LR
22
+ A[Project-owned approved source] --> B[Project-owned sanitization]
23
+ B --> C[Immutable baseline]
24
+ D[Project migrations] --> E[Digest planner]
25
+ C --> F[Disposable local Supabase]
26
+ E --> F
27
+ F --> G[Project application proof]
28
+ G --> H[Verified local receipt]
29
+ ```
30
+
31
+ The reusable package owns the path from a completed baseline plus migration directory to
32
+ a verified local runtime. The consuming project owns everything that decides which source
33
+ data is allowed, how it is transformed, and what application behavior counts as correct.
@@ -0,0 +1,33 @@
1
+ # Designing a production source boundary
2
+
3
+ The npm package does not connect to production and does not ship an extraction command.
4
+ That separation is a security boundary: each project must authorize, sanitize, and
5
+ audit its own source.
6
+
7
+ ## Recommended flow
8
+
9
+ 1. Define versioned read-only export views containing only approved columns.
10
+ 2. Grant a temporary role `SELECT` on those views and nothing else.
11
+ 3. Use a short-lived credential outside shell history and source control.
12
+ 4. Stream records through the project-owned sanitization policy.
13
+ 5. Write into a private building generation below `.rehearsal`.
14
+ 6. Verify counts, checksums, policy coverage, migration history, and secret canaries.
15
+ 7. Atomically activate the completed generation.
16
+ 8. Revoke and verify removal of the temporary credential.
17
+ 9. Delete raw intermediate files and retain only the sanitized artifact.
18
+
19
+ Use server-side cursors or another bounded streaming mechanism. A full in-memory dump
20
+ is not acceptable for large sources. Extraction logs should contain counts and hashes,
21
+ never row bodies.
22
+
23
+ ## What not to do
24
+
25
+ - Do not point `rehearsal.config.ts` at a hosted URL.
26
+ - Do not put a production connection string in `.rehearsal/runtime.env`.
27
+ - Do not grant table-wide access merely because a view is inconvenient.
28
+ - Do not commit sanitized baselines; sanitized data is still data.
29
+ - Do not let the reusable package infer which fields are safe.
30
+ - Do not leave the export role provisioned after refresh.
31
+
32
+ The local execution engine remains useful with synthetic or manually approved baselines.
33
+ Production-shaped onboarding is a separate project security exercise.
@@ -0,0 +1,79 @@
1
+ # Release process
2
+
3
+ Rehearsal publishes from a reviewed GitHub release through the protected `npm`
4
+ environment. The workflow builds and hashes the candidate before the environment
5
+ approval gate, then publishes those exact bytes with npm provenance. A local working
6
+ tree is never the release source.
7
+
8
+ The initial publishable `0.1.0-beta.1` release branch is the first change allowed to set
9
+ `"private": false`. Publication still requires the exact protected-main tag, prerelease
10
+ flag, artifact checks, and protected `npm` environment gate described below.
11
+
12
+ `0.1.0-beta.0` was prepared under the unavailable `@rehearsal` npm scope and was never
13
+ published. `0.1.0-beta.1` supersedes that candidate under `@rehearsal-db/core` without
14
+ rewriting the earlier Git tag or GitHub prerelease.
15
+
16
+ ## One-time first-package bootstrap
17
+
18
+ npm trusted publishing and staged publishing are package-level settings, so they cannot
19
+ be configured until `@rehearsal-db/core` exists in the registry. The first public version has
20
+ a deliberately narrower bootstrap path:
21
+
22
+ 1. The npm owner enables 2FA and creates or confirms the public `@rehearsal-db` organization
23
+ scope. Do not send a password, OTP, recovery code, or access token to another person.
24
+ 2. After the reviewed release change reaches protected `main`, the owner creates the
25
+ exact `v0.1.0-beta.1` GitHub release and marks it as a prerelease. The prepare job runs without npm credentials,
26
+ packs the tag, and uploads its versioned tarball plus SHA-1 and SHA-256 metadata. The
27
+ publish job waits at the protected environment and cannot run yet.
28
+ 3. The owner downloads or inspects that prepared artifact, confirms its version and
29
+ checksum, and explicitly authorizes those exact bytes.
30
+ 4. Only then, the owner creates a short-lived granular npm token with read/write access
31
+ limited to the `@rehearsal-db` scope and **Bypass 2FA** enabled. npm requires that bypass
32
+ for a non-interactive first publish; the environment approval remains the human
33
+ release gate. Store the token only as the `NPM_TOKEN` secret in the protected GitHub
34
+ `npm` environment.
35
+ 5. The owner approves the waiting `npm` deployment. GitHub Actions publishes the exact
36
+ uploaded tarball with provenance. The workflow
37
+ refuses to use the bootstrap secret for any version other than `0.1.0-beta.1`.
38
+ 6. Immediately after the registry verification passes, the owner deletes the GitHub
39
+ environment secret and revokes the temporary npm token.
40
+ 7. From the new package's npm settings, configure the trusted GitHub Actions publisher
41
+ for repository `Ddupasquier/rehearsal-db`, workflow `publish.yml`, and environment
42
+ `npm`. Allow direct `npm publish` for this workflow because the protected GitHub
43
+ environment supplies the human gate. A later switch to npm staged publication must
44
+ change and prove the workflow before narrowing the trusted publisher permission.
45
+ 8. Set package publishing access to require 2FA and disallow traditional tokens.
46
+
47
+ This bootstrap token is a one-release compromise imposed by npm's package-creation
48
+ boundary. It is never committed, printed, copied into a ticket, or retained for later
49
+ versions.
50
+
51
+ ## Every release candidate
52
+
53
+ 1. Start from protected `main` on a dedicated ticketed release branch.
54
+ 2. Verify the exact version, changelog, compatibility notes, and packed file list.
55
+ 3. Run unit and contract tests, formatting, package-content and secret audits,
56
+ dependency audit, clean tarball installation, and the installed Docker fixture.
57
+ 4. Have a developer unfamiliar with the implementing project follow the clean-project
58
+ onboarding. Correct and retest the first confusing, missing, or wrong instruction.
59
+ 5. Change `private` to `false` only in the reviewed release change.
60
+ 6. Record the exact tarball filename, SHA-1, SHA-256, allowlisted files, unpacked size,
61
+ executable, and zero-runtime-dependency result.
62
+ 7. Obtain explicit publication authorization for that exact version and artifact.
63
+ 8. Merge the approved release commit through protected `main` and create the exact
64
+ `v<package-version>` tag and GitHub release.
65
+ 9. Review and approve the protected `npm` deployment only after its prepare job matches
66
+ the approved version and checksum.
67
+ 10. Verify public visibility, ownership, provenance, registry SHA-1, README rendering,
68
+ exact-version clean installation, CLI execution, signatures, and the unrelated
69
+ installed Docker fixture.
70
+ 11. Replace consuming projects' temporary Git/archive references only on their own
71
+ protected integration branches and rerun their complete verification.
72
+
73
+ The workflow publishes prereleases under the `beta` dist-tag and refuses a stable
74
+ version. A stable tag requires a later contract, compatibility, and release decision.
75
+
76
+ Creating the repository, passing CI, extracting the engine, merging a release branch,
77
+ or creating a tag does not authorize npm publication. Publication requires explicit
78
+ authorization for the exact packed artifact, and the protected GitHub environment
79
+ supplies the final human gate.
@@ -0,0 +1,69 @@
1
+ # Sanitization policy
2
+
3
+ Rehearsal deliberately does not decide what your application may copy. The consuming
4
+ project owns an exhaustive, reviewable policy for its export surface.
5
+
6
+ Every exported field should receive one action:
7
+
8
+ - `KEEP`: retain an explicitly non-sensitive value needed for realistic behavior;
9
+ - `PSEUDONYMIZE`: replace identity while preserving stable joins;
10
+ - `REPLACE`: substitute a safe value of compatible shape;
11
+ - `EXCLUDE`: omit data that the rehearsal does not need;
12
+ - `DERIVE`: create a bounded safe value from approved inputs.
13
+
14
+ Fail if a new column is unclassified. Do not default unknown fields to `KEEP`.
15
+
16
+ The package exports `validateSanitizationCoverage` and
17
+ `applySanitizationAction` as generic primitives:
18
+
19
+ ```ts
20
+ import {
21
+ applySanitizationAction,
22
+ validateSanitizationCoverage,
23
+ } from "@rehearsal-db/core";
24
+
25
+ validateSanitizationCoverage({ policy, schemaTables });
26
+
27
+ const safeValue = applySanitizationAction({
28
+ action: column.action,
29
+ value: sourceValue,
30
+ pseudonymize: projectPseudonymizer,
31
+ replace: projectReplacement,
32
+ derive: projectDerivation,
33
+ context: { table: table.name, column: column.name },
34
+ });
35
+ ```
36
+
37
+ Coverage validation requires a one-to-one table and column match: missing and unknown
38
+ entries both fail. The package supplies the operation contract; the project supplies
39
+ the schema inventory, keys, replacements, and derivation logic.
40
+
41
+ ## Stable identity
42
+
43
+ Use keyed, deterministic pseudonyms when relationships must survive across tables.
44
+ Keep the key outside source control and outside the final baseline. The same source ID
45
+ should map consistently within a generation, while the original value cannot be
46
+ recovered from the artifact.
47
+
48
+ ## High-risk fields
49
+
50
+ Exclude or replace secrets, password material, refresh tokens, session tokens, payment
51
+ data, private messages, precise location, raw uploads, provider credentials, and
52
+ unbounded free text unless a reviewed test requirement proves they are necessary.
53
+
54
+ Images and Storage objects need the same classification as database columns. A public
55
+ product image may be retained under its license; a private upload generally may not.
56
+
57
+ ## Validation
58
+
59
+ Before activation, verify:
60
+
61
+ 1. every exported column is classified;
62
+ 2. prohibited values and secret canaries are absent;
63
+ 3. referential relationships required by the app remain valid;
64
+ 4. row counts match the approved export manifest;
65
+ 5. the policy digest is recorded in the baseline manifest;
66
+ 6. raw staging files and temporary credentials are removed.
67
+
68
+ Completeness is not correctness. Human review of the policy and export boundary remains
69
+ mandatory before any real source is introduced.
@@ -0,0 +1,40 @@
1
+ # Security model
2
+
3
+ Rehearsal assumes a mistake is more likely than an attacker. Its design makes ordinary
4
+ misconfiguration fail closed before a state-changing operation.
5
+
6
+ ## Trust boundaries
7
+
8
+ The engine trusts the reviewed package code, strict project configuration, a verified
9
+ active baseline, exact migration bytes, and explicitly project-owned proof code. It does
10
+ not trust ambient environment variables, hosted project state, unknown config fields,
11
+ changed migration history, incomplete artifacts, or an unverified runtime.
12
+
13
+ ## Independent barriers
14
+
15
+ - loopback-only application and service URLs;
16
+ - a dedicated unlinked Supabase workdir and project ID;
17
+ - exact non-overlapping local ports;
18
+ - a clean child-process environment that omits hosted credentials;
19
+ - immutable baseline files and checksums;
20
+ - exact migration-prefix and candidate digests;
21
+ - local runtime labels used for bounded stop/removal;
22
+ - successful receipts written only after verification.
23
+
24
+ No single environment variable or config edit should redirect the tool to production.
25
+ Version 1 provides no hosted execution mode.
26
+
27
+ ## Identity providers
28
+
29
+ An optional external identity handshake is distinct from database access. Only declared
30
+ credential names are read from an ignored owner-only file, and the callback must target
31
+ local Auth. The local account may represent a sanitized production identity, but its
32
+ session and writes remain local.
33
+
34
+ ## Remaining responsibilities
35
+
36
+ Rehearsal cannot prove that retained data is lawful, a sanitization rule is ethically
37
+ appropriate, a migration has the intended business meaning, or a project adapter is
38
+ safe. Repository owners must review those decisions and protect artifacts.
39
+
40
+ Report vulnerabilities using the private process in the root security policy.