@rehearsal-db/core 0.1.0-beta.1 → 0.1.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +244 -1
- package/COMPATIBILITY.md +17 -0
- package/README.md +139 -346
- package/SECURITY.md +2 -1
- package/SUPPORT.md +5 -0
- package/docs/README.md +29 -0
- package/docs/adapters.md +20 -6
- package/docs/architecture.md +58 -0
- package/docs/baselines.md +102 -22
- package/docs/commands.md +196 -33
- package/docs/configuration.md +258 -13
- package/docs/getting-started.md +106 -182
- package/docs/glossary.md +11 -8
- package/docs/production-source.md +176 -33
- package/docs/releasing.md +28 -38
- package/docs/roadmap.md +41 -0
- package/docs/runtime-policies.md +193 -0
- package/docs/sanitization.md +43 -8
- package/docs/security-model.md +34 -9
- package/docs/standalone-workflow.md +107 -0
- package/docs/troubleshooting.md +102 -2
- package/docs/tutorial.md +70 -59
- package/package.json +30 -22
- package/scripts/runtime/manage_database.mjs +18 -0
- package/src/README.md +17 -0
- package/src/application/session.mjs +435 -0
- package/{scripts/lib/rehearsal/baseline_artifact.mjs → src/baseline/artifact.mjs} +142 -17
- package/{scripts/lib/rehearsal/baseline_builder.mjs → src/baseline/builder.mjs} +19 -10
- package/src/baseline/input_discovery.mjs +155 -0
- package/src/baseline/policy_review.mjs +92 -0
- package/src/baseline/preparation.mjs +323 -0
- package/src/baseline/privacy_engine.mjs +413 -0
- package/{scripts/lib/rehearsal → src/baseline}/sanitization_policy.mjs +133 -3
- package/{scripts/lib/rehearsal → src/baseline}/schema_snapshot.mjs +1 -1
- package/src/cli/arguments.mjs +123 -0
- package/src/cli/guided.mjs +812 -0
- package/src/cli/rehearsal.mjs +997 -0
- package/src/cli/renderers.mjs +584 -0
- package/src/cli/runtime_commands.mjs +624 -0
- package/src/cli/source_commands.mjs +326 -0
- package/src/cli/terminal.mjs +275 -0
- package/src/identity/claim.mjs +975 -0
- package/src/identity/storage.mjs +165 -0
- package/{scripts/lib/rehearsal → src/project}/configuration.d.mts +72 -4
- package/src/project/configuration.mjs +1199 -0
- package/src/project/setup.mjs +379 -0
- package/src/project/support_report.mjs +105 -0
- package/src/runtime/cleanup.mjs +381 -0
- package/{scripts/lib/rehearsal → src/runtime}/plan.mjs +118 -20
- package/src/runtime/policy.mjs +438 -0
- package/{scripts/lib/rehearsal/runtime_restore.mjs → src/runtime/restore.mjs} +46 -27
- package/src/runtime/topology.mjs +177 -0
- package/{scripts/lib/rehearsal → src/shared}/diagnostics.mjs +10 -3
- package/src/shared/human_output.mjs +4 -0
- package/src/shared/operation_guard.mjs +162 -0
- package/{scripts/lib/rehearsal → src/shared}/process_environment.mjs +5 -1
- package/src/source/access.mjs +578 -0
- package/src/source/asset_transfer.mjs +177 -0
- package/src/source/baseline.mjs +446 -0
- package/src/source/postgresql_access.mjs +480 -0
- package/src/targets/postgresql.mjs +808 -0
- package/{scripts/operations/database/manage_rehearsal_database.mjs → src/targets/supabase.mjs} +66 -20
- package/{scripts/lib/environment/local_supabase.mjs → src/targets/supabase_environment.mjs} +60 -28
- package/src/targets/target.mjs +66 -0
- package/scripts/lib/rehearsal/configuration.mjs +0 -559
- package/scripts/operations/rehearsal/rehearsal_cli.mjs +0 -565
- /package/{scripts/lib/rehearsal → src/runtime}/migration_history.mjs +0 -0
- /package/{scripts/lib/rehearsal → src/runtime}/service_environment.mjs +0 -0
package/docs/releasing.md
CHANGED
|
@@ -5,48 +5,27 @@ environment. The workflow builds and hashes the candidate before the environment
|
|
|
5
5
|
approval gate, then publishes those exact bytes with npm provenance. A local working
|
|
6
6
|
tree is never the release source.
|
|
7
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
8
|
`0.1.0-beta.0` was prepared under the unavailable `@rehearsal` npm scope and was never
|
|
13
9
|
published. `0.1.0-beta.1` supersedes that candidate under `@rehearsal-db/core` without
|
|
14
10
|
rewriting the earlier Git tag or GitHub prerelease.
|
|
15
11
|
|
|
16
|
-
##
|
|
12
|
+
## Trusted publication boundary
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
a
|
|
14
|
+
`@rehearsal-db/core` trusts only the GitHub Actions publisher for repository
|
|
15
|
+
`Ddupasquier/rehearsal-db`, workflow `publish.yml`, and environment `npm`. The publish job
|
|
16
|
+
requests a short-lived GitHub OIDC identity after the protected environment approval;
|
|
17
|
+
it does not read an npm token or retain a registry credential. Package publishing access
|
|
18
|
+
requires 2FA and disallows bypass tokens.
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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.
|
|
20
|
+
The initial `0.1.0-beta.1` package creation required a one-time bootstrap credential
|
|
21
|
+
because npm cannot configure a trusted publisher before a package exists. That
|
|
22
|
+
credential is not part of the maintained release architecture: it was deleted from the
|
|
23
|
+
GitHub environment after publication, must remain revoked at npm, and cannot be consumed
|
|
24
|
+
by this workflow.
|
|
46
25
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
26
|
+
Direct `npm publish` is allowed only for this trusted publisher because the protected
|
|
27
|
+
GitHub `npm` environment supplies the human gate. A later switch to npm staged
|
|
28
|
+
publication must change and prove the workflow before narrowing that permission.
|
|
50
29
|
|
|
51
30
|
## Every release candidate
|
|
52
31
|
|
|
@@ -58,7 +37,7 @@ versions.
|
|
|
58
37
|
onboarding. Correct and retest the first confusing, missing, or wrong instruction.
|
|
59
38
|
5. Change `private` to `false` only in the reviewed release change.
|
|
60
39
|
6. Record the exact tarball filename, SHA-1, SHA-256, allowlisted files, unpacked size,
|
|
61
|
-
executable,
|
|
40
|
+
executable, declared runtime dependency inventory, and dependency audit result.
|
|
62
41
|
7. Obtain explicit publication authorization for that exact version and artifact.
|
|
63
42
|
8. Merge the approved release commit through protected `main` and create the exact
|
|
64
43
|
`v<package-version>` tag and GitHub release.
|
|
@@ -66,12 +45,23 @@ versions.
|
|
|
66
45
|
the approved version and checksum.
|
|
67
46
|
10. Verify public visibility, ownership, provenance, registry SHA-1, README rendering,
|
|
68
47
|
exact-version clean installation, CLI execution, signatures, and the unrelated
|
|
69
|
-
installed Docker fixture.
|
|
48
|
+
installed Docker fixture. Allow up to six minutes for a first package to propagate
|
|
49
|
+
through the public registry before classifying a missing packument as a release
|
|
50
|
+
failure.
|
|
70
51
|
11. Replace consuming projects' temporary Git/archive references only on their own
|
|
71
52
|
protected integration branches and rerun their complete verification.
|
|
72
53
|
|
|
73
54
|
The workflow publishes prereleases under the `beta` dist-tag and refuses a stable
|
|
74
|
-
version.
|
|
55
|
+
version. While Rehearsal has no stable release, the workflow also moves `latest` to the
|
|
56
|
+
same reviewed beta. This keeps the npm package page and the ordinary
|
|
57
|
+
`npm install @rehearsal-db/core` command current. When Rehearsal gains a stable release,
|
|
58
|
+
`latest` must switch to the stable line while `beta` continues to identify prereleases.
|
|
59
|
+
|
|
60
|
+
The trusted publisher allows `npm dist-tag` only so this workflow can maintain those two
|
|
61
|
+
tags without a stored npm token. A manual workflow run from `main` can repair the tags
|
|
62
|
+
for the exact prerelease version currently recorded in `package.json`; it cannot publish
|
|
63
|
+
a package or select a different version. The protected `npm` environment still supplies
|
|
64
|
+
the human approval gate.
|
|
75
65
|
|
|
76
66
|
Creating the repository, passing CI, extracting the engine, merging a release branch,
|
|
77
67
|
or creating a tag does not authorize npm publication. Publication requires explicit
|
package/docs/roadmap.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Next steps
|
|
2
|
+
|
|
3
|
+
Rehearsal supports guided Supabase and ordinary PostgreSQL migration rehearsals. The
|
|
4
|
+
current development track removes the need for consumer-owned Rehearsal engines while
|
|
5
|
+
keeping application meaning and privacy decisions project-owned.
|
|
6
|
+
|
|
7
|
+
## Standalone workflow
|
|
8
|
+
|
|
9
|
+
The implementation sequence is dependency-driven:
|
|
10
|
+
|
|
11
|
+
1. exact temporary source access and retirement;
|
|
12
|
+
2. bounded coherent extraction and executable privacy rules;
|
|
13
|
+
3. approved Storage assets and declarative restore prerequisites;
|
|
14
|
+
4. verified local identity association;
|
|
15
|
+
5. ordinary application launch and meaningful positive/negative proofs;
|
|
16
|
+
6. onboarding, upgrade safety, and exact packaged-artifact acceptance.
|
|
17
|
+
|
|
18
|
+
These capabilities stay behind separate review boundaries. Normal runtime commands never
|
|
19
|
+
receive source credentials. Source-side writes, package publication, consumer cleanup,
|
|
20
|
+
and real provider observation each require their own authorization.
|
|
21
|
+
|
|
22
|
+
Track the full breakdown in
|
|
23
|
+
[standalone roadmap issue #38](https://github.com/Ddupasquier/rehearsal-db/issues/38).
|
|
24
|
+
|
|
25
|
+
## Acceptance still required
|
|
26
|
+
|
|
27
|
+
- Install the exact packed candidate in clean Supabase and PostgreSQL consumers.
|
|
28
|
+
- Exercise two unrelated synthetic schemas, bounded large data, interruption, drift,
|
|
29
|
+
invalid migrations, identities, images, persistence, reset, and cleanup.
|
|
30
|
+
- Run the released package in the real reporting consumer and record positives and
|
|
31
|
+
negatives.
|
|
32
|
+
- Directly observe any claimed Google account-picker/callback and unfamiliar-developer
|
|
33
|
+
onboarding behavior; automation cannot invent that evidence.
|
|
34
|
+
- Remove consumer integration code only after its replacement passes and that deletion
|
|
35
|
+
is separately approved.
|
|
36
|
+
|
|
37
|
+
## Later database targets
|
|
38
|
+
|
|
39
|
+
After the PostgreSQL family is stable in real projects, evaluate individual PostgreSQL
|
|
40
|
+
services. MySQL, MongoDB, and unrelated database families require different migration,
|
|
41
|
+
restore, and safety behavior and remain out of scope.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Runtime and identity policies
|
|
2
|
+
|
|
3
|
+
These optional JSON files replace common project-owned Rehearsal adapters. They contain
|
|
4
|
+
declarations only: unknown fields, SQL, JavaScript, and unsupported extensions fail.
|
|
5
|
+
|
|
6
|
+
## Runtime policy
|
|
7
|
+
|
|
8
|
+
Point `runtimePolicy` in `rehearsal.config.mjs` to a reviewed file:
|
|
9
|
+
|
|
10
|
+
```json
|
|
11
|
+
{
|
|
12
|
+
"policyVersion": 1,
|
|
13
|
+
"prerequisites": {
|
|
14
|
+
"schemas": ["extensions"],
|
|
15
|
+
"extensions": [{ "name": "pgcrypto", "schema": "extensions" }]
|
|
16
|
+
},
|
|
17
|
+
"triggers": [
|
|
18
|
+
{
|
|
19
|
+
"name": "profile_after_auth_insert",
|
|
20
|
+
"table": { "schema": "auth", "name": "users" },
|
|
21
|
+
"timing": "after",
|
|
22
|
+
"events": ["insert"],
|
|
23
|
+
"function": { "schema": "public", "name": "handle_new_user" }
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"localRows": [
|
|
27
|
+
{
|
|
28
|
+
"table": { "schema": "public", "name": "runtime_settings" },
|
|
29
|
+
"keyColumns": ["name"],
|
|
30
|
+
"values": { "name": "scheduler_enabled", "value": false }
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"table": { "schema": "public", "name": "app_role_assignments" },
|
|
34
|
+
"keyColumns": ["user_id"],
|
|
35
|
+
"values": {
|
|
36
|
+
"user_id": "11111111-1111-4111-8111-111111111111",
|
|
37
|
+
"role": "owner"
|
|
38
|
+
},
|
|
39
|
+
"identityAssociation": {
|
|
40
|
+
"identity": "approved-owner",
|
|
41
|
+
"column": "user_id"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"expectations": [
|
|
46
|
+
{
|
|
47
|
+
"table": { "schema": "public", "name": "profiles" },
|
|
48
|
+
"rowLevelSecurity": true,
|
|
49
|
+
"columns": [{ "name": "id", "generated": false, "identity": false }],
|
|
50
|
+
"foreignKeys": [],
|
|
51
|
+
"policies": []
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Restore order is fixed: Rehearsal creates named schemas and allowlisted extensions
|
|
58
|
+
before dependent schema objects, adds declared triggers after their tables and functions
|
|
59
|
+
exist, then inserts local-only rows after baseline data. Application schema remains in
|
|
60
|
+
immutable migrations or the verified schema snapshot. Verification checks extensions,
|
|
61
|
+
triggers, local-only rows, columns, generated/identity behavior, foreign keys, named RLS
|
|
62
|
+
policies, RLS state, and unvalidated constraints.
|
|
63
|
+
|
|
64
|
+
Use `identityAssociation` when a local seed is intentionally transferred by a named
|
|
65
|
+
identity policy. Verification accepts the configured placeholder before association and
|
|
66
|
+
the exact recorded local identity afterward. Rehearsal stores that mapping only in its
|
|
67
|
+
local internal schema; it does not duplicate the old role or weaken the row check.
|
|
68
|
+
|
|
69
|
+
## Identity policy
|
|
70
|
+
|
|
71
|
+
The identity policy links one verified local Supabase identity to a copied pseudonymous
|
|
72
|
+
graph without an application callback patch:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"identityVersion": 1,
|
|
77
|
+
"identities": [
|
|
78
|
+
{
|
|
79
|
+
"name": "approved-owner",
|
|
80
|
+
"provider": "google",
|
|
81
|
+
"emailEnvironmentVariable": "REHEARSAL_APPROVED_OWNER_EMAIL",
|
|
82
|
+
"approvedEmailSha256": "<sha256 of the lowercase approved email>",
|
|
83
|
+
"placeholderUserId": "11111111-1111-4111-8111-111111111111",
|
|
84
|
+
"references": [
|
|
85
|
+
{
|
|
86
|
+
"schema": "public",
|
|
87
|
+
"table": "profiles",
|
|
88
|
+
"column": "user_id",
|
|
89
|
+
"required": true
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"schema": "public",
|
|
93
|
+
"table": "app_role_assignments",
|
|
94
|
+
"column": "user_id",
|
|
95
|
+
"required": true
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"schema": "public",
|
|
99
|
+
"table": "food_compatibility_feedback",
|
|
100
|
+
"column": "reviewed_by",
|
|
101
|
+
"required": true,
|
|
102
|
+
"strategy": "preserve-audit"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"jsonReferences": [
|
|
106
|
+
{
|
|
107
|
+
"schema": "public",
|
|
108
|
+
"table": "events",
|
|
109
|
+
"column": "payload",
|
|
110
|
+
"path": ["actor_id"]
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"signupDefaults": [
|
|
114
|
+
{
|
|
115
|
+
"table": { "schema": "public", "table": "profiles" },
|
|
116
|
+
"identityColumn": "user_id",
|
|
117
|
+
"ignoredColumns": ["created_at", "updated_at"],
|
|
118
|
+
"values": {
|
|
119
|
+
"display_name": {
|
|
120
|
+
"kind": "pattern",
|
|
121
|
+
"pattern": "^User[0-9]{14}$"
|
|
122
|
+
},
|
|
123
|
+
"avatar_path": null
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"pathReferences": [
|
|
128
|
+
{
|
|
129
|
+
"schema": "public",
|
|
130
|
+
"table": "profiles",
|
|
131
|
+
"column": "avatar_path",
|
|
132
|
+
"valueType": "text"
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"assets": [
|
|
136
|
+
{
|
|
137
|
+
"bucket": "avatars",
|
|
138
|
+
"prefix": "11111111-1111-4111-8111-111111111111/",
|
|
139
|
+
"rewritePath": true
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
"claims": { "rehearsal_owner": true },
|
|
143
|
+
"tokenHook": {
|
|
144
|
+
"function": {
|
|
145
|
+
"schema": "public",
|
|
146
|
+
"name": "custom_access_token_hook"
|
|
147
|
+
},
|
|
148
|
+
"expectedClaims": { "app_role": "developer" }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The email stays in an environment variable; only its reviewed hash is committed. Run
|
|
156
|
+
`rehearsal open`, complete the ordinary local Google sign-in, and stop the app with
|
|
157
|
+
`Ctrl+C`. Then preview and confirm the association:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npx rehearsal identity plan --identity=approved-owner
|
|
161
|
+
npx rehearsal identity claim --identity=approved-owner \
|
|
162
|
+
--confirm-identity=<full-sha256>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Rehearsal requires exactly one verified matching local provider identity. Every
|
|
166
|
+
`required` reference must exist after transfer. Declare application role tables as
|
|
167
|
+
references; `claims` alone is not a replacement for a database-backed token hook.
|
|
168
|
+
|
|
169
|
+
References use `"strategy": "transfer"` by default. Use `"preserve-audit"` only for
|
|
170
|
+
immutable historical authorship, such as a completed review. Rehearsal leaves that row
|
|
171
|
+
and its synthetic Auth actor unchanged, but still transfers the active profile, roles,
|
|
172
|
+
and other declared data. Undeclared references still stop the claim.
|
|
173
|
+
|
|
174
|
+
`signupDefaults` resolves a copied-profile collision only when the local row's complete
|
|
175
|
+
non-ignored shape matches. List every remaining column. Use ignored columns only for
|
|
176
|
+
server-managed values such as timestamps. An edited value, extra column, ambiguous row,
|
|
177
|
+
or unrelated local application data rolls back the entire claim.
|
|
178
|
+
|
|
179
|
+
`rewritePath` copies approved Storage objects through the local Supabase Storage API,
|
|
180
|
+
verifies the destination bytes, updates the declared database paths, and then removes
|
|
181
|
+
the old objects. A database failure removes the new copies and leaves the originals
|
|
182
|
+
usable. Restored objects may begin with either the placeholder owner or no owner;
|
|
183
|
+
another owner is refused. `pathReferences` updates matching text or JSONB pointers. A
|
|
184
|
+
configured `tokenHook` must return the declared claim subset before commit. The browser must then
|
|
185
|
+
refresh its session or sign in again because Rehearsal cannot rewrite an issued JWT.
|
|
186
|
+
Run `rehearsal open` again for that fresh-session check; runtime data is preserved.
|
|
187
|
+
|
|
188
|
+
The transaction does not import production passwords, sessions, refresh tokens,
|
|
189
|
+
cookies, MFA secrets, or provider credentials. Local MFA and authorization rules remain
|
|
190
|
+
real.
|
|
191
|
+
|
|
192
|
+
A synthetic test can prove the plumbing and refusal controls. Claim that Google account
|
|
193
|
+
selection or callback behavior works only after directly observing that real flow.
|
package/docs/sanitization.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Sanitization policy
|
|
2
2
|
|
|
3
|
-
Rehearsal
|
|
4
|
-
|
|
3
|
+
Rehearsal never decides what your application may copy. The project owner reviews an
|
|
4
|
+
exhaustive policy; the package validates and executes the supported recipes.
|
|
5
5
|
|
|
6
6
|
Every exported field should receive one action:
|
|
7
7
|
|
|
@@ -13,8 +13,39 @@ Every exported field should receive one action:
|
|
|
13
13
|
|
|
14
14
|
Fail if a new column is unclassified. Do not default unknown fields to `KEEP`.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
For runtime restore, each included column must also classify whether it is generated,
|
|
17
|
+
whether it is an identity column, and its foreign-key target or explicit absence. Run
|
|
18
|
+
`rehearsal baseline prepare` to create a shape-only draft from synthetic NDJSON. The
|
|
19
|
+
draft uses `REVIEW REQUIRED` placeholders and cannot be activated until they are
|
|
20
|
+
replaced and the `draft` marker is removed.
|
|
21
|
+
|
|
22
|
+
Tables default to the `public` schema. Add `"schema": "app_api"` beside `name`
|
|
23
|
+
for another schema. Schema plus table is the identity, so two schemas may safely contain
|
|
24
|
+
tables with the same name.
|
|
25
|
+
|
|
26
|
+
In an interactive terminal, the guided **Review the script** action works table by table.
|
|
27
|
+
For larger tables, a human can explicitly apply safe defaults (`REPLACE`, `NEVER`
|
|
28
|
+
generated, `NO` identity, and no foreign key), then review only exceptions. Likely
|
|
29
|
+
structural columns such as `id`, `*_id`, and timestamps start selected as exceptions.
|
|
30
|
+
Users can instead review every column individually. Retaining a value is explicitly
|
|
31
|
+
labeled as sensitive, every saved field remains classified, and no preset is silently
|
|
32
|
+
applied. The reviewer validates the completed policy and refuses to overwrite a draft
|
|
33
|
+
changed during the session.
|
|
34
|
+
|
|
35
|
+
Two policy versions exist:
|
|
36
|
+
|
|
37
|
+
- Version 1 describes data that a project has already made safe. It remains supported
|
|
38
|
+
for synthetic/local inputs and existing baselines.
|
|
39
|
+
- Version 2 is required by `baseline refresh`. It adds bounded declarative recipes so
|
|
40
|
+
Rehearsal can sanitize without project callbacks.
|
|
41
|
+
|
|
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.
|
|
46
|
+
|
|
47
|
+
The package still exports `validateSanitizationCoverage` and
|
|
48
|
+
`applySanitizationAction` for existing version 1 preparation tools:
|
|
18
49
|
|
|
19
50
|
```ts
|
|
20
51
|
import {
|
|
@@ -35,15 +66,15 @@ const safeValue = applySanitizationAction({
|
|
|
35
66
|
```
|
|
36
67
|
|
|
37
68
|
Coverage validation requires a one-to-one table and column match: missing and unknown
|
|
38
|
-
entries both fail.
|
|
39
|
-
|
|
69
|
+
entries both fail. New standalone preparation should use the version 2 engine described
|
|
70
|
+
in [Production source](production-source.md).
|
|
40
71
|
|
|
41
72
|
## Stable identity
|
|
42
73
|
|
|
43
74
|
Use keyed, deterministic pseudonyms when relationships must survive across tables.
|
|
44
|
-
Keep the key outside source control and
|
|
75
|
+
Keep the key under `.rehearsal`, outside source control and the final baseline. The same source ID
|
|
45
76
|
should map consistently within a generation, while the original value cannot be
|
|
46
|
-
recovered from the artifact.
|
|
77
|
+
recovered from the artifact. The manifest records only the key fingerprint.
|
|
47
78
|
|
|
48
79
|
## High-risk fields
|
|
49
80
|
|
|
@@ -67,3 +98,7 @@ Before activation, verify:
|
|
|
67
98
|
|
|
68
99
|
Completeness is not correctness. Human review of the policy and export boundary remains
|
|
69
100
|
mandatory before any real source is introduced.
|
|
101
|
+
|
|
102
|
+
The exact reviewed policy bytes are checksum-bound to the active baseline. Planning,
|
|
103
|
+
candidate inspection, and runtime restore refuse to continue if that file later changes;
|
|
104
|
+
build a new reviewed baseline instead of editing the active policy in place.
|
package/docs/security-model.md
CHANGED
|
@@ -5,24 +5,39 @@ misconfiguration fail closed before a state-changing operation.
|
|
|
5
5
|
|
|
6
6
|
## Trust boundaries
|
|
7
7
|
|
|
8
|
-
The engine trusts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
The engine trusts reviewed package code, strict declarations, a verified active baseline,
|
|
9
|
+
and exact migration bytes. It does not trust ambient environment variables, hosted
|
|
10
|
+
project state, unknown fields, changed history, incomplete artifacts, or an unverified
|
|
11
|
+
runtime.
|
|
12
12
|
|
|
13
13
|
## Independent barriers
|
|
14
14
|
|
|
15
15
|
- loopback-only application and service URLs;
|
|
16
|
-
- a dedicated unlinked Supabase workdir and
|
|
16
|
+
- a dedicated unlinked Supabase workdir, or an exactly named and labeled PostgreSQL
|
|
17
|
+
container and volume;
|
|
17
18
|
- exact non-overlapping local ports;
|
|
18
19
|
- a clean child-process environment that omits hosted credentials;
|
|
19
20
|
- immutable baseline files and checksums;
|
|
20
21
|
- exact migration-prefix and candidate digests;
|
|
21
22
|
- local runtime labels used for bounded stop/removal;
|
|
23
|
+
- PostgreSQL images must already exist locally and are never pulled implicitly;
|
|
24
|
+
- plain PostgreSQL receives a fresh random password per disposable runtime, retained
|
|
25
|
+
only in owner-readable ignored runtime files;
|
|
22
26
|
- successful receipts written only after verification.
|
|
27
|
+
- separate exact-digest approval for source setup, source retirement, and identity claim;
|
|
28
|
+
- short-lived source readers limited to reviewed views/columns and deny checks;
|
|
29
|
+
- bounded read-only extraction with no raw dump or row-value logging;
|
|
30
|
+
- exhaustive privacy policy version 2 with an owner-only local pseudonym key;
|
|
31
|
+
- application children receive only explicit local mappings and stay in an owned process
|
|
32
|
+
group.
|
|
33
|
+
- only one state-changing Rehearsal command may own a project at a time; stale locks are
|
|
34
|
+
recovered after their process exits;
|
|
35
|
+
- a state-changing command fingerprints its installed Rehearsal package and refuses to
|
|
36
|
+
continue if that installation changes while the command is running.
|
|
23
37
|
|
|
24
|
-
No single environment variable or config edit
|
|
25
|
-
|
|
38
|
+
No single environment variable or config edit can redirect runtime commands to
|
|
39
|
+
production. Optional source preparation is a separate boundary and never provides a
|
|
40
|
+
hosted execution mode.
|
|
26
41
|
|
|
27
42
|
## Identity providers
|
|
28
43
|
|
|
@@ -31,10 +46,20 @@ credential names are read from an ignored owner-only file, and the callback must
|
|
|
31
46
|
local Auth. The local account may represent a sanitized production identity, but its
|
|
32
47
|
session and writes remain local.
|
|
33
48
|
|
|
49
|
+
Account association is one local transaction. Rehearsal removes a signup-created row
|
|
50
|
+
only when its complete declared default shape still matches, refuses unrelated local
|
|
51
|
+
application data, verifies required role references and an optional token hook, and can
|
|
52
|
+
copy, byte-check, and retire only declared placeholder-owned Storage paths. Immutable
|
|
53
|
+
audit references may explicitly retain their synthetic historical actor. Rehearsal also
|
|
54
|
+
refuses to rewrite application paths when copied records refer to files that are absent
|
|
55
|
+
from local Storage. Existing browser JWTs still require an ordinary refresh or new
|
|
56
|
+
sign-in.
|
|
57
|
+
|
|
34
58
|
## Remaining responsibilities
|
|
35
59
|
|
|
36
60
|
Rehearsal cannot prove that retained data is lawful, a sanitization rule is ethically
|
|
37
|
-
appropriate, a migration has the intended business meaning, or a
|
|
38
|
-
|
|
61
|
+
appropriate, a migration has the intended business meaning, or a real provider flow was
|
|
62
|
+
observed. Repository owners must review those decisions and protect artifacts. The
|
|
63
|
+
configuration barriers are not an operating-system firewall.
|
|
39
64
|
|
|
40
65
|
Report vulnerabilities using the private process in the root security policy.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Standalone workflow contract
|
|
2
|
+
|
|
3
|
+
Rehearsal's normal commands remain local-only. `run`, `start`, `reset`,
|
|
4
|
+
`migrate`, `verify`, and `cleanup` never receive source credentials and never
|
|
5
|
+
connect to a hosted database.
|
|
6
|
+
|
|
7
|
+
The optional preparation workflow is a separate security boundary. It has
|
|
8
|
+
three deliberately separate phases:
|
|
9
|
+
|
|
10
|
+
1. `source plan` reads declarations and produces a redacted, exact plan.
|
|
11
|
+
2. `source apply` requires the plan digest and source-owner credentials from a
|
|
12
|
+
named environment variable. It creates only the declared, time-limited
|
|
13
|
+
reader and export surface.
|
|
14
|
+
3. `refresh` uses that reader in a read-only repeatable-read transaction, builds
|
|
15
|
+
privately, activates only after verification, resets the local runtime, and applies
|
|
16
|
+
reviewed retention. `baseline refresh` is the lower-level baseline-only form.
|
|
17
|
+
|
|
18
|
+
`source retire` has its own preview and digest. It removes only the exact
|
|
19
|
+
reader and export objects Rehearsal recorded. It never searches for similarly
|
|
20
|
+
named roles or removes unrelated grants.
|
|
21
|
+
|
|
22
|
+
## What belongs in declarations
|
|
23
|
+
|
|
24
|
+
Projects declare application meaning; Rehearsal executes it. Declarations may
|
|
25
|
+
name:
|
|
26
|
+
|
|
27
|
+
- approved source relations and columns;
|
|
28
|
+
- whether rows are approved public data or belong to one explicitly approved
|
|
29
|
+
owner;
|
|
30
|
+
- privacy actions and bounded transformation recipes;
|
|
31
|
+
- licensed or consented Storage buckets and prefixes;
|
|
32
|
+
- schema and extension prerequisites;
|
|
33
|
+
- local identities and reference locations;
|
|
34
|
+
- ordinary application commands and observable proof expectations.
|
|
35
|
+
|
|
36
|
+
Declarations cannot contain JavaScript callbacks, SQL fragments, passwords,
|
|
37
|
+
tokens, production URLs, or automatic consent decisions. Unknown fields,
|
|
38
|
+
tables, columns, recipes, JSON keys, and target identities fail closed.
|
|
39
|
+
|
|
40
|
+
## Credential separation
|
|
41
|
+
|
|
42
|
+
Provisioning, extraction, asset, provider, and local-runtime credentials are
|
|
43
|
+
separate. A declaration contains only the name of an environment variable or
|
|
44
|
+
owner-only secret file. Rehearsal never puts credential values in command-line
|
|
45
|
+
arguments, reports, baselines, receipts, or a launched application.
|
|
46
|
+
|
|
47
|
+
The current workflow creates and verifies its own temporary PostgreSQL reader. An
|
|
48
|
+
externally provisioned reader is not yet accepted because Rehearsal cannot currently
|
|
49
|
+
prove that reader's complete scope and retirement behavior.
|
|
50
|
+
|
|
51
|
+
## Snapshot and privacy guarantees
|
|
52
|
+
|
|
53
|
+
Database schema, migration evidence, and selected rows are read in one
|
|
54
|
+
read-only repeatable-read PostgreSQL transaction. Rehearsal rechecks the source
|
|
55
|
+
identity and migration evidence before commit. Rows stream in bounded batches;
|
|
56
|
+
record bodies never appear in progress or error output.
|
|
57
|
+
|
|
58
|
+
Storage objects do not share the database transaction guarantee. Their inventory records
|
|
59
|
+
size and version metadata; transfer requires that version, verifies the exact byte count,
|
|
60
|
+
and records a SHA-256 in the immutable baseline. Transfer refuses an object that changes,
|
|
61
|
+
exceeds its declared limit, or falls outside an approved bucket and prefix.
|
|
62
|
+
|
|
63
|
+
Privacy policy version 2 is executable without project sanitizer code. It
|
|
64
|
+
supports exact keep, exclusion, keyed pseudonyms, constants, and a small set of
|
|
65
|
+
documented derivations. Policies classify every selected field and supported
|
|
66
|
+
nested JSON key. A new or unknown field blocks refresh until the policy is
|
|
67
|
+
reviewed again.
|
|
68
|
+
|
|
69
|
+
The pseudonym key is an owner-only local secret. It is not stored in the
|
|
70
|
+
baseline or source control. Receipts bind the policy bytes, schema shape,
|
|
71
|
+
source scope, migration evidence, and key fingerprint without storing the key
|
|
72
|
+
or source identifiers.
|
|
73
|
+
|
|
74
|
+
## Restore, identities, and applications
|
|
75
|
+
|
|
76
|
+
Restore performs only supported declarative prerequisites. Application schema
|
|
77
|
+
changes remain immutable migration files; configuration is never an arbitrary
|
|
78
|
+
privileged-SQL escape hatch.
|
|
79
|
+
|
|
80
|
+
Local identities never reuse production sessions, refresh tokens, password
|
|
81
|
+
hashes, provider secrets, or MFA material. An approved provider association is
|
|
82
|
+
performed inside the local runtime and must match the reviewed receipt.
|
|
83
|
+
|
|
84
|
+
Rehearsal launches ordinary project commands with a minimal environment and
|
|
85
|
+
generated local connection files. It verifies every configured dependency
|
|
86
|
+
before launch, owns only the child process group it starts, and does not claim
|
|
87
|
+
to provide an operating-system firewall.
|
|
88
|
+
|
|
89
|
+
Proofs require explicit positives and negatives. A process starting, a non-5xx
|
|
90
|
+
response, an empty 200, a 401, or a 404 cannot satisfy a declared positive.
|
|
91
|
+
Reports distinguish engine readiness, dependency readiness, proof completion,
|
|
92
|
+
and provider behavior that was directly observed by a person.
|
|
93
|
+
|
|
94
|
+
## Failure and upgrade behavior
|
|
95
|
+
|
|
96
|
+
- Failed, interrupted, changed-policy, low-disk, or drifted refreshes leave the
|
|
97
|
+
prior active baseline and any edited runtime untouched.
|
|
98
|
+
- Setup and upgrades preview exact file changes and never overwrite a reviewed
|
|
99
|
+
policy, config, baseline, or local edit silently.
|
|
100
|
+
- Reset, discard, and cleanup operate only on purpose-created Rehearsal
|
|
101
|
+
resources and retain their existing exact-preview protections.
|
|
102
|
+
- Rehearsal does not make legal, consent, licensing, backup, disaster-recovery,
|
|
103
|
+
universal-database, or OS-firewall guarantees.
|
|
104
|
+
|
|
105
|
+
The final acceptance gate uses the exact packed or published artifact in clean
|
|
106
|
+
Supabase and PostgreSQL consumers. Consumer integration code is removed only
|
|
107
|
+
after that replacement is proved and the removal is separately approved.
|