@rehearsal-db/core 0.1.0-beta.13 → 0.1.0-beta.14

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 CHANGED
@@ -5,6 +5,82 @@ a Changelog, and versions will follow Semantic Versioning after the package exis
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## [0.1.0-beta.14] - 2026-10-05
9
+
10
+ ### Added
11
+
12
+ - Packed-package onboarding is now a required CI job. It covers fresh Supabase and
13
+ PostgreSQL installs, beta.7 configuration preservation, missing credentials, occupied
14
+ ports, malformed configuration, and non-destructive partial-setup recovery.
15
+ - The independent test lab can run the same first-install boundary against an exact
16
+ candidate tarball before either database lifecycle.
17
+ - Installation and setup now report the exact active Rehearsal configuration path and
18
+ explain when a supported existing nested config prevents root-file generation.
19
+ - Packed-package onboarding covers fresh, nested, existing-root, and repeated installs
20
+ while proving reviewed configuration bytes are preserved.
21
+ - Privacy policy version 2 can explicitly treat nullable owners as non-matches and match
22
+ an approved owner through any of a bounded list of pseudonymized identity columns.
23
+ - Bounded JSON unions classify each permitted root type, while JSON dictionaries require
24
+ reviewed runtime-key formats, key actions, value recipes, and item/depth/byte limits.
25
+ - JSON dictionaries can restrict runtime keys to canonical signed integers within an
26
+ explicit safe-integer range, preserving positive, negative, and reviewed zero keys
27
+ without widening numeric maps to arbitrary text.
28
+ - Date shifting can explicitly preserve numeric epoch-millisecond representation,
29
+ including inside structured JSON, while sharing a stable grouped offset with related
30
+ epoch or ISO-string dates.
31
+ - Bounded scalar enums retain only explicitly reviewed structural strings, finite
32
+ numbers, or booleans inside ordinary fields and nested JSON declarations, rejecting
33
+ out-of-domain values without echoing them in diagnostics.
34
+ - Validated strings preserve bounded, case-sensitive structural codes from open domains
35
+ using a package-owned portable alphabet, refusing credential-shaped and malformed
36
+ text without consumer regexes, callbacks, or static identifier lists.
37
+ - Keyed hexadecimal and GTIN pseudonyms preserve reviewed database constraints, while
38
+ fixed-width digest recipes derive fingerprints only from explicitly named sanitized
39
+ columns and reject missing, excluded, duplicate, or cyclic inputs.
40
+ - A single GTIN recipe can declare reviewed `allowedLengths`, preserving each source
41
+ value's 8-, 12-, 13-, or 14-digit shape and check digit even inside structured JSON.
42
+ - Keyed URL pseudonyms replace private HTTPS URLs with deterministic, bounded HTTPS
43
+ loopback paths without retaining source hosts, paths, credentials, queries, or tokens.
44
+ - Bounded binding substitution can retain permitted surrounding text while replacing
45
+ exact occurrences of a reviewed UUID with its corresponding keyed UUID pseudonym.
46
+ - External PostgreSQL readers can declare a bounded exact allowlist of provider-owned
47
+ permission groups. Rehearsal verifies safe membership options, group attributes,
48
+ nesting, view ownership, and the complete effective privilege surface.
49
+
50
+ ### Documentation
51
+
52
+ - First-time users now have a short recovery table for interrupted setup, failed
53
+ upgrades, port conflicts, missing OAuth credentials, and low Docker capacity.
54
+ - The configuration guide documents a safe manual move to the project root, separating
55
+ config-file-relative JavaScript imports from project-root-relative Rehearsal paths.
56
+ - The sanitization guide documents nullable and multi-column ownership, heterogeneous
57
+ JSON values, runtime-keyed dictionaries, keyed HTTPS replacements, bounded identity
58
+ substitution, and their fail-closed boundaries.
59
+
60
+ ### Fixed
61
+
62
+ - Source preparation now stores and reads each target's access receipt and owner-only
63
+ reader credential under its configured baseline artifact directory. Nested and
64
+ multi-target state roots no longer collide, and retirement refuses a receipt from a
65
+ different target root.
66
+ - Supabase Storage source preparation now recursively traverses real folder placeholder
67
+ entries while keeping the approved prefix, path, depth, object-count, per-object, and
68
+ total-byte boundaries fail closed.
69
+ - Approved-owner selection now rejects non-finite numeric values in every declared
70
+ owner column before choosing a privacy branch, including when another column already
71
+ matches the approved owner.
72
+ - Pseudonymized canonical integer dictionary keys now share the same keyed identity
73
+ mapping as numeric columns and nested numeric values using the same namespace, so
74
+ runtime maps keep their reviewed cross-representation joins.
75
+ - External-reader membership mismatches now return a redacted, actionable source
76
+ authorization refusal instead of an internal-failure diagnostic.
77
+ - All external-reader privilege, expiration, readable-surface, and security-definer
78
+ denials now use the same `SOURCE_AUTHORIZATION_REFUSED` diagnostic and exit code 3.
79
+ - Identity claims now sequence PostgreSQL reads on their single transaction client,
80
+ avoiding deprecated overlapping queries and remaining compatible with pg 9.
81
+
82
+ ## [0.1.0-beta.13] - 2026-10-05
83
+
8
84
  ### Added
9
85
 
10
86
  - Runtime and CI compatibility now cover maintained Node.js 22, 24, and 26 releases;
package/README.md CHANGED
@@ -45,7 +45,9 @@ For an ordinary npm application install, Rehearsal safely creates a commented
45
45
  `rehearsal.config.mjs` in the project root, adds only its local-artifact entries to
46
46
  `.gitignore`, and prepares the isolated local runtime configuration. It detects the
47
47
  project name, database target, migration paths, commands, and free ports. Review lines
48
- marked `CHECK`, then open the guide. Existing files are never overwritten.
48
+ marked `CHECK`, then open the guide. Existing files are never overwritten. If a supported
49
+ root or nested config already exists, Rehearsal reports that active path and does not
50
+ create a competing file; see [Configuration](docs/configuration.md#workspaces-and-custom-paths).
49
51
 
50
52
  If install scripts are disabled or the workspace root is ambiguous, installation makes
51
53
  no guess. Run `npx rehearsal` inside the application and choose **Set the stage** for the
@@ -130,15 +130,20 @@ All paths resolve inside the consuming project. The artifact directory must be n
130
130
  `.rehearsal`; this is an intentional deletion guard. `runtimeWorkdir` must be its
131
131
  `runtime` child, and the generated application environment file must remain inside it.
132
132
 
133
- Rehearsal never overwrites this config. To start over, move the existing file somewhere
134
- safe, run setup again, and compare the two files before deleting either one.
135
-
133
+ Rehearsal never overwrites this config. Do not move it merely to inspect a newer template.
136
134
  After upgrading, run `npx rehearsal init` to print the current release's generated
137
135
  template beside the path of your existing config. This comparison is read-only; adding a
138
136
  new optional key remains your decision. `npx rehearsal init --write` still refuses to
139
137
  replace an existing config. Rehearsal lists important optional settings that are
140
138
  available but not enabled before printing the template, so they are easier to find.
141
139
 
140
+ If setup was interrupted after creating only some files, rerun
141
+ `npx rehearsal setup --write`. It recreates missing generated files while preserving every
142
+ existing config and local runtime file. When a config itself is invalid, keep it as a
143
+ backup, generate a fresh file, and manually carry over only reviewed settings. See
144
+ [Getting started](getting-started.md#if-setup-or-an-upgrade-is-interrupted) for the short
145
+ recovery table.
146
+
142
147
  ### Workspaces and custom paths
143
148
 
144
149
  For an npm workspace, automatic creation proceeds only when exactly one application
@@ -151,8 +156,38 @@ checkout never receive project files.
151
156
 
152
157
  Supported existing config paths—including
153
158
  `infrastructure/rehearsal/rehearsal.config.mjs`—are preserved, and a second root config
154
- is not created. Use `--config=<project-relative-path>` for other explicit paths when
155
- running commands.
159
+ is not created. The install hook reports the exact active path when npm displays lifecycle
160
+ output, and setup always prints it. `npx rehearsal init --json` is the package-manager-
161
+ independent way to check the `destination`. Rehearsal checks the supported root filenames
162
+ first and then the supported nested filenames; finding any one of them prevents automatic
163
+ creation of another. Use
164
+ `--config=<project-relative-path>` for other explicit paths when running commands.
165
+
166
+ ### Move an existing config to the project root
167
+
168
+ Relocation is deliberately manual because the config may contain reviewed settings and
169
+ JavaScript imports. Rehearsal will never move it or create a competing root file.
170
+
171
+ From the directory containing `package.json`:
172
+
173
+ 1. Stop active Rehearsal commands and confirm the current path with
174
+ `npx rehearsal init --json`.
175
+ 2. Make a backup outside every supported discovery path, such as
176
+ `.rehearsal/config-backups/rehearsal.config.mjs`.
177
+ 3. Move—do not copy—the active file to `./rehearsal.config.mjs`. Use `git mv` when it is
178
+ tracked so review history remains clear.
179
+ 4. Update relative JavaScript `import` specifiers inside the moved file. Imports resolve
180
+ from the config file's own folder, so a nested `../../something.mjs` import usually
181
+ changes after moving to the root.
182
+ 5. Leave config values such as `migrationDirectory`, `sanitizationPolicy`,
183
+ `runtimePolicy`, `identityPolicy`, and `dependentTargets[].configPath` unchanged unless
184
+ the referenced project file also moved. Rehearsal resolves those values from the
185
+ project root, not from the config file's folder.
186
+ 6. Run `npx rehearsal init --json`, confirm its `destination` is
187
+ `rehearsal.config.mjs`, then run `npx rehearsal doctor` and review the Git diff.
188
+
189
+ If validation fails, restore the backup to its original path. Do not run setup while the
190
+ move is half-finished; setup may correctly conclude that no supported config exists.
156
191
 
157
192
  `preparation.privacyKey` must stay inside `.rehearsal`; it is ignored and owner-readable
158
193
  only. Source, runtime, and identity policy files are declarations that may be reviewed in
@@ -48,6 +48,11 @@ especially:
48
48
  - the application start and proof commands;
49
49
  - the local ports.
50
50
 
51
+ If a supported configuration already exists elsewhere—such as
52
+ `infrastructure/rehearsal/rehearsal.config.mjs`—the installer reports that exact active
53
+ path and does not generate a competing root file. Keep using it, or follow the explicit
54
+ [root relocation guide](configuration.md#move-an-existing-config-to-the-project-root).
55
+
51
56
  If lifecycle scripts were disabled, a global/cache install was used, or a workspace has
52
57
  more than one possible application, no project files are created automatically. Run
53
58
  `npx rehearsal` inside the intended application, choose **Set the stage**, select
@@ -180,6 +185,29 @@ config during an upgrade. After upgrading, run `npx rehearsal init` to see impor
180
185
  optional settings you have not enabled and compare your file with the installed
181
186
  release's current template.
182
187
 
188
+ ### If setup or an upgrade is interrupted
189
+
190
+ Do not delete `.rehearsal/` or your existing config. Start with:
191
+
192
+ ```bash
193
+ npx rehearsal doctor
194
+ npx rehearsal init
195
+ ```
196
+
197
+ Use the reported problem to choose the smallest recovery:
198
+
199
+ | Problem | Safe recovery |
200
+ | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
201
+ | A generated runtime file is missing | Run `npx rehearsal setup --write`. Existing files stay unchanged; only missing files are created. |
202
+ | A port is already in use | Stop the conflicting local process or choose new dedicated ports, then rerun setup. |
203
+ | The config is malformed | Move it to a backup name, run `npx rehearsal setup --write`, then copy reviewed choices into the new file. |
204
+ | OAuth credentials are missing | Create the ignored file named by `supabase.authentication.environmentFile`, add only the declared keys, and run `chmod 600` on it. Ambient shell credentials are not used. |
205
+ | An npm upgrade fails | Keep the existing config, baseline, and lockfile. Restore dependencies with your package manager, then run `npx rehearsal init` before retrying. |
206
+ | Docker storage is low | Run `npx rehearsal cleanup` for an exact preview. Rehearsal never performs a global Docker prune or silently removes volumes. |
207
+
208
+ `setup --write` and package installation never replace a config. If an existing file is
209
+ invalid, Rehearsal fails closed and leaves it available for comparison.
210
+
183
211
  ## Files Rehearsal creates
184
212
 
185
213
  - `rehearsal.config.mjs` — reviewed project configuration
@@ -23,6 +23,15 @@ The privacy key stays ignored under `.rehearsal`. The policy is safe to review i
23
23
  control because it contains hashes and environment-variable names, not credentials,
24
24
  URLs, or raw owner identifiers.
25
25
 
26
+ `credentialFile` must be inside the selected target's
27
+ `baseline.artifactDirectory`, under its `secrets` folder. With the default artifact
28
+ directory, use `.rehearsal/secrets/source-reader.env`. For a target whose artifact
29
+ directory is `targets/primary/.rehearsal`, use
30
+ `targets/primary/.rehearsal/secrets/source-reader.env` and place `privacyKey` there as
31
+ well. Rehearsal stores that target's access receipt beside its baseline at
32
+ `targets/primary/.rehearsal/source-access-receipt.json`; separate targets never share
33
+ the receipt or credential.
34
+
26
35
  ## 2. Declare the source boundary
27
36
 
28
37
  `source-access-policy.json` uses this shape:
@@ -112,6 +121,7 @@ an administrator credential or change the source:
112
121
  "reader": {
113
122
  "mode": "external",
114
123
  "role": "provided_rehearsal_reader",
124
+ "allowedMemberships": ["provided_rehearsal_readers"],
115
125
  "connectionEnvironmentVariable": "REHEARSAL_SOURCE_READER_URL",
116
126
  "credentialFile": ".rehearsal/secrets/source-reader.env",
117
127
  "maximumValidForMinutes": 30
@@ -153,9 +163,25 @@ view hash, columns, scopes, or reader declaration requires a new verification.
153
163
 
154
164
  External mode also requires all non-system readable columns to match only the declared
155
165
  views and migration-ledger columns. It refuses database, schema, relation, or column
156
- writes; inherited roles; privileged role attributes; executable non-system
157
- security-definer functions; a reader-owned view; or a database-enforced expiration
158
- beyond `maximumValidForMinutes`.
166
+ writes; privileged role attributes; executable non-system security-definer functions;
167
+ a reader-owned view; or a database-enforced expiration beyond
168
+ `maximumValidForMinutes`.
169
+
170
+ This audit is intentionally conservative: an object-level table, column, sequence, or
171
+ function grant remains disallowed even when its schema currently lacks `USAGE`. Do not
172
+ use schema visibility to hide stale grants. Revoke the object grant or move the approved
173
+ surface behind the reviewed export views; this also avoids relying on behavior of an
174
+ already-open or prepared database session.
175
+
176
+ An external login may inherit its narrow permissions from provider-owned group roles.
177
+ List every direct group in `allowedMemberships`; omit the field or use `[]` when the
178
+ login has direct grants only. Rehearsal requires the observed membership set to match
179
+ that list exactly. Every allowed group must be non-login and non-privileged, grant
180
+ inheritance to the login, disable both `SET ROLE` and membership delegation, inherit no
181
+ other role, and own none of the export views. PostgreSQL versions that cannot prove the
182
+ per-membership role-switch setting are refused. Rehearsal still evaluates the login's
183
+ complete effective read, write, sequence, and executable-function surface after those
184
+ checks. Adding, removing, or changing a group changes the reviewed plan digest.
159
185
 
160
186
  `targetSchema` is optional and defaults to `public`. Set it when the restored relation
161
187
  belongs elsewhere, and use the same schema in privacy policy version 2. This is relation
@@ -167,6 +193,9 @@ non-identity prefix may use `prefix`. A private owner prefix uses
167
193
  the privacy policy below. Its raw value stays out of tracked files and the review plan
168
194
  records only its SHA-256. Objects outside the exact bucket/prefix are not listed or
169
195
  downloaded. Size, object-count, path, ETag, and exact-byte checks apply.
196
+ Supabase folder entries are traversed recursively beneath that exact prefix. Folder
197
+ entries count toward `maximumObjects`, so the same reviewed limit bounds both the
198
+ directory walk and transferred files. Empty files remain files and are copied normally.
170
199
 
171
200
  ## 3. Use executable privacy policy version 2
172
201
 
@@ -227,10 +256,12 @@ Every selected column has one action and, where required, a bounded recipe:
227
256
  }
228
257
  ```
229
258
 
230
- Supported recipes are intentionally small: keyed UUID/email/text/integer pseudonyms,
231
- explicit constants, bounded or grouped date shifts, identity-aware path mappings, and
232
- fully classified JSON objects. Unknown tables, columns, JSON keys, formats, and recipes
233
- stop the refresh. There is no JavaScript or SQL escape hatch. See
259
+ Supported recipes are intentionally small: keyed UUID/email/text/integer/hex/GTIN/URL
260
+ pseudonyms, hexadecimal digests of explicitly named sanitized columns, explicit
261
+ constants, bounded or grouped date shifts, identity-aware path mappings, bounded
262
+ reviewed-identity substitution inside retained text, and fully classified JSON
263
+ structures. Unknown tables, columns, digest inputs, JSON keys, formats, and recipes stop
264
+ the refresh. There is no JavaScript or SQL escape hatch. See
234
265
  [Sanitization policy](sanitization.md) for complete path and date examples.
235
266
 
236
267
  ## 4. Preview, apply, refresh, and retire
@@ -290,6 +321,11 @@ limits access, and the provider may revoke it sooner. Rehearsal does not claim t
290
321
  cleanup revoked a provider-owned credential. Unrelated roles, grants, objects, baselines,
291
322
  runtimes, and Docker resources are preserved.
292
323
 
324
+ Apply, refresh, and retire always resolve those local files from the active config's
325
+ `baseline.artifactDirectory`. If you switch configs or target roots, Rehearsal refuses
326
+ to retire a receipt from the other target. It also refuses an existing receipt or
327
+ credential rather than overwriting or adopting it.
328
+
293
329
  ## Limits
294
330
 
295
331
  Rehearsal does not decide consent, licensing, retention rights, privileged-role meaning,
package/docs/releasing.md CHANGED
@@ -32,9 +32,11 @@ publication must change and prove the workflow before narrowing that permission.
32
32
  1. Start from protected `main` on a dedicated ticketed release branch.
33
33
  2. Verify the exact version, changelog, compatibility notes, and packed file list.
34
34
  3. Run unit and contract tests, formatting, package-content and secret audits,
35
- dependency audit, clean tarball installation, and the installed Docker fixture.
36
- 4. Have a developer unfamiliar with the implementing project follow the clean-project
37
- onboarding. Correct and retest the first confusing, missing, or wrong instruction.
35
+ dependency audit, packed onboarding, clean tarball installation, and the installed
36
+ Docker fixtures.
37
+ 4. When an unfamiliar developer is available, have them follow clean-project onboarding.
38
+ Correct and retest the first confusing, missing, or wrong instruction. Record when
39
+ this human observation was unavailable; automated checks must not impersonate it.
38
40
  5. Change `private` to `false` only in the reviewed release change.
39
41
  6. Record the exact tarball filename, SHA-1, SHA-256, allowlisted files, unpacked size,
40
42
  executable, declared runtime dependency inventory, and dependency audit result.
package/docs/roadmap.md CHANGED
@@ -29,8 +29,9 @@ Track the full breakdown in
29
29
  invalid migrations, identities, images, persistence, reset, and cleanup.
30
30
  - Run the released package in the real reporting consumer and record positives and
31
31
  negatives.
32
- - Directly observe any claimed Google account-picker/callback and unfamiliar-developer
33
- onboarding behavior; automation cannot invent that evidence.
32
+ - Directly observe any claimed Google account-picker/callback. Record
33
+ unfamiliar-developer onboarding behavior when a tester is available; automation cannot
34
+ invent either kind of human evidence.
34
35
  - Remove consumer integration code only after its replacement passes and that deletion
35
36
  is separately approved.
36
37