@rehearsal-db/core 0.1.0-beta.10 → 0.1.0-beta.12

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.
@@ -40,9 +40,110 @@ Two policy versions exist:
40
40
  Rehearsal can sanitize without project callbacks.
41
41
 
42
42
  Version 2 supports keyed UUID, email, text, and integer pseudonyms; explicit constant
43
- replacement; bounded date shifting; and exhaustively classified JSON objects. Unknown
44
- tables, columns, nested keys, formats, recipes, or missing fields fail closed. It never
45
- evaluates JavaScript or SQL from the policy.
43
+ replacement; bounded date shifting; approved-owner conditionals; exhaustively classified
44
+ JSON objects; and bounded JSON arrays. Unknown tables, columns, nested keys, formats,
45
+ recipes, or missing required fields fail closed. It never evaluates JavaScript or SQL
46
+ from the policy.
47
+
48
+ ## Approved-owner values
49
+
50
+ Keep the raw approved owner outside the policy and baseline. The policy stores only its
51
+ environment-variable name and SHA-256 receipt:
52
+
53
+ ```json
54
+ {
55
+ "bindings": {
56
+ "approved-owner": {
57
+ "environmentVariable": "REHEARSAL_APPROVED_OWNER_ID",
58
+ "approvedValueSha256": "<lowercase sha256 of the exact owner value>"
59
+ }
60
+ },
61
+ "tables": [
62
+ {
63
+ "name": "profiles",
64
+ "sourceRows": "STREAM AND SANITIZE",
65
+ "ownerBinding": { "binding": "approved-owner", "column": "user_id" },
66
+ "columns": [
67
+ {
68
+ "name": "user_id",
69
+ "action": "PSEUDONYMIZE",
70
+ "recipe": { "format": "uuid", "namespace": "account-id" },
71
+ "generated": "NEVER",
72
+ "identity": "YES",
73
+ "foreignKey": null
74
+ },
75
+ {
76
+ "name": "display_name",
77
+ "action": "DERIVE",
78
+ "recipe": {
79
+ "kind": "approved-owner",
80
+ "approved": { "action": "KEEP" },
81
+ "otherwise": {
82
+ "action": "REPLACE",
83
+ "recipe": { "kind": "constant", "value": "Synthetic account" }
84
+ }
85
+ },
86
+ "generated": "NEVER",
87
+ "identity": "NO",
88
+ "foreignKey": null
89
+ }
90
+ ]
91
+ }
92
+ ]
93
+ }
94
+ ```
95
+
96
+ Generate the receipt without putting the owner value in shell history:
97
+
98
+ ```sh
99
+ node -e 'const {createHash}=require("node:crypto"); process.stdout.write(createHash("sha256").update(process.env.REHEARSAL_APPROVED_OWNER_ID).digest("hex")+"\n")'
100
+ ```
101
+
102
+ Every conditional table names its owner column. Missing bindings, hash mismatches,
103
+ missing owner columns, null/unsupported owner values, and conditionals without an owner
104
+ binding are refused. The owner column must be marked `identity: "YES"` and use
105
+ `PSEUDONYMIZE`, preventing a conditional policy from retaining raw account IDs. Other
106
+ owners take the declared `otherwise` path; every other identity-bearing field still
107
+ needs its own pseudonymization declaration. Supply the binding only to the local
108
+ server-side Rehearsal process; do not put it in the policy, baseline, or tracked files.
109
+
110
+ ## Structured JSON
111
+
112
+ `json-object` fields are required by default. Set `"required": false` on an explicitly
113
+ optional field. Unknown keys remain errors. `json-array` declares one item recipe and a
114
+ required `maximumItems`. Both recipes accept `maximumDepth`, `maximumBytes`, and
115
+ `allowNull`; defaults are 8 levels, 65,536 bytes, and no null container. Bounds are
116
+ checked before producing the transformed structure. Nested objects and arrays repeat
117
+ the same declarations, and every nested identity uses an explicit pseudonym recipe.
118
+
119
+ ```json
120
+ {
121
+ "action": "DERIVE",
122
+ "recipe": {
123
+ "kind": "json-array",
124
+ "maximumItems": 25,
125
+ "maximumDepth": 4,
126
+ "maximumBytes": 8192,
127
+ "items": {
128
+ "action": "DERIVE",
129
+ "recipe": {
130
+ "kind": "json-object",
131
+ "fields": {
132
+ "actor_id": {
133
+ "action": "PSEUDONYMIZE",
134
+ "recipe": { "format": "uuid", "namespace": "account-id" }
135
+ },
136
+ "note": {
137
+ "action": "REPLACE",
138
+ "required": false,
139
+ "recipe": { "kind": "constant", "value": "Synthetic note" }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ ```
46
147
 
47
148
  The package still exports `validateSanitizationCoverage` and
48
149
  `applySanitizationAction` for existing version 1 preparation tools:
@@ -28,6 +28,8 @@ name:
28
28
  - whether rows are approved public data or belong to one explicitly approved
29
29
  owner;
30
30
  - privacy actions and bounded transformation recipes;
31
+ - hashed server-side owner bindings and explicit approved/other-owner branches;
32
+ - bounded nested JSON objects and arrays with required/optional fields;
31
33
  - licensed or consented Storage buckets and prefixes;
32
34
  - schema and extension prerequisites;
33
35
  - local identities and reference locations;
@@ -20,6 +20,20 @@ npx rehearsal --help
20
20
 
21
21
  Do not use `sudo` or require a global install.
22
22
 
23
+ ## Installation did not create `rehearsal.config.mjs`
24
+
25
+ Rehearsal intentionally skips automatic creation when install scripts are disabled, the
26
+ install is global or temporary, or more than one workspace application could own the
27
+ config. From the intended application directory, run:
28
+
29
+ ```bash
30
+ npx rehearsal
31
+ ```
32
+
33
+ Choose **Set the stage** and approve the preview. For pnpm and Yarn, use this guided path;
34
+ automatic root generation is currently tested with npm. An existing supported config is
35
+ kept in place, including `infrastructure/rehearsal/rehearsal.config.mjs`.
36
+
23
37
  ## Setup says Node.js 24 is required
24
38
 
25
39
  Rehearsal intentionally supports one maintained Node.js major in its first beta. Switch
@@ -132,9 +146,31 @@ changes.
132
146
 
133
147
  ## Local authentication fails
134
148
 
135
- Confirm the provider is enabled in the dedicated local Supabase config, the allowlisted
136
- service environment file exists with owner-only permissions, and the provider callback
137
- is the local Auth callback. Do not paste provider secrets into config or terminal output.
149
+ For Google or GitHub, confirm `supabase.authentication` is declared in
150
+ `rehearsal.config.mjs`, its ignored environment file exists with `chmod 600`, and the
151
+ provider has the printed local Auth callback registered. Rehearsal generates the
152
+ disposable Supabase provider block.
153
+
154
+ When migrating from the legacy service environment fields, replace those fields together
155
+ with `supabase.authentication` and rerun `rehearsal doctor`. A compatible Google or
156
+ GitHub provider section may remain in the tracked template: Rehearsal supersedes it only
157
+ inside the generated runtime copy. Doctor refuses unknown provider settings, duplicate
158
+ or nested provider sections, and nonce or optional-email settings that do not match the
159
+ new declaration. Keep both options false unless there is a reviewed provider-specific
160
+ need; skipping nonce validation reduces replay protection. Otherwise keep using the
161
+ documented legacy configuration.
162
+ Never paste provider secrets into tracked config or terminal output.
163
+
164
+ If `identity plan` refuses the matcher, read the message literally:
165
+
166
+ - **Provider or matcher type is unsupported:** use only the combinations documented in
167
+ [Runtime and identity policies](runtime-policies.md).
168
+ - **No verified identity matches:** complete an ordinary local sign-in, confirm the
169
+ correct environment value is present, then run the plan again.
170
+ - **More than one identity matches:** narrow the provider allowlist or use a hashed
171
+ provider-subject matcher. Rehearsal will not guess between accounts.
172
+ - **Provider subject conflicts:** the local Auth identity disagrees with itself; remove
173
+ and recreate that disposable local sign-in instead of forcing a claim.
138
174
 
139
175
  ## Runtime changes disappeared
140
176
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rehearsal-db/core",
3
- "version": "0.1.0-beta.10",
3
+ "version": "0.1.0-beta.12",
4
4
  "private": false,
5
5
  "description": "Safely rehearse PostgreSQL and Supabase migrations against sanitized, production-shaped data.",
6
6
  "repository": {
@@ -10,7 +10,7 @@
10
10
  "bugs": {
11
11
  "url": "https://github.com/Ddupasquier/rehearsal-db/issues"
12
12
  },
13
- "homepage": "https://github.com/Ddupasquier/rehearsal-db#readme",
13
+ "homepage": "https://ddupasquier.github.io/rehearsal-db/",
14
14
  "publishConfig": {
15
15
  "access": "public",
16
16
  "tag": "beta",
@@ -40,6 +40,7 @@
40
40
  },
41
41
  "files": [
42
42
  "src",
43
+ "scripts/install/create_root_config.mjs",
43
44
  "scripts/runtime/manage_database.mjs",
44
45
  "docs/*.md",
45
46
  "README.md",
@@ -51,6 +52,9 @@
51
52
  "LICENSE"
52
53
  ],
53
54
  "scripts": {
55
+ "postinstall": "node scripts/install/create_root_config.mjs",
56
+ "docs:build": "node scripts/docs/build.mjs",
57
+ "docs:preview": "node scripts/docs/serve.mjs",
54
58
  "test": "vitest run",
55
59
  "test:unit": "vitest run tests/unit",
56
60
  "test:integration": "vitest run tests/integration tests/contracts",
@@ -58,8 +62,10 @@
58
62
  "test:fixture": "node scripts/verification/fixtures/supabase.mjs",
59
63
  "test:fixture:postgresql": "node scripts/verification/fixtures/postgresql.mjs",
60
64
  "test:fixture:dependent": "node scripts/verification/fixtures/dependent.mjs",
65
+ "test:fixture:onboarding": "node scripts/verification/fixtures/onboarding.mjs",
61
66
  "test:fixture:standalone": "node scripts/verification/fixtures/standalone.mjs",
62
- "check": "npm run check:syntax && npm run test && npm run format:check && npm run package:audit",
67
+ "test:fixture:privacy": "node scripts/verification/fixtures/privacy.mjs",
68
+ "check": "npm run check:syntax && npm run test && npm run docs:build && npm run format:check && npm run package:audit",
63
69
  "check:syntax": "find src scripts tests -type f -name '*.mjs' -exec node --check {} +",
64
70
  "format": "prettier --write .",
65
71
  "format:check": "prettier --check .",
@@ -78,7 +84,10 @@
78
84
  "pg": "^8.23.1"
79
85
  },
80
86
  "devDependencies": {
87
+ "@fontsource-variable/dm-sans": "^5.3.0",
88
+ "@fontsource-variable/fraunces": "^5.3.0",
81
89
  "@lydell/node-pty": "^1.2.0-beta.15",
90
+ "marked": "^18.0.14",
82
91
  "prettier": "^3.9.6",
83
92
  "vitest": "^5.0.2"
84
93
  }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /** Create safe project-root Rehearsal scaffolding during a local install. */
3
+
4
+ import { fileURLToPath } from "node:url";
5
+ import { createInstalledRehearsalScaffold } from "../../src/project/install_scaffold.mjs";
6
+
7
+ const packageRoot = fileURLToPath(new URL("../..", import.meta.url));
8
+
9
+ try {
10
+ const result = await createInstalledRehearsalScaffold({ packageRoot });
11
+ if (result.status === "ready") {
12
+ const changed = result.files.filter((file) => file.action !== "unchanged");
13
+ console.log(
14
+ [
15
+ "Rehearsal is ready in this project.",
16
+ ...(changed.length
17
+ ? [
18
+ ...changed.map(
19
+ (file) =>
20
+ ` ${file.action === "create" ? "+" : "~"} ${file.path}`,
21
+ ),
22
+ ]
23
+ : [" Existing Rehearsal configuration preserved."]),
24
+ "Next: review rehearsal.config.mjs, then run npx rehearsal.",
25
+ ].join("\n"),
26
+ );
27
+ } else {
28
+ console.log(
29
+ `Rehearsal did not create project files: ${result.reason}.\nNext: run npx rehearsal from the application directory.`,
30
+ );
31
+ }
32
+ } catch (error) {
33
+ console.warn(
34
+ `Rehearsal could not safely create project files during installation: ${String(error?.message ?? error)}\nNext: run npx rehearsal from the application directory.`,
35
+ );
36
+ }