-
Notifications
You must be signed in to change notification settings - Fork 6
(TML-2397) M3 — Contract spaces: cipherstash extension as a contract space #439
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
5db1ffe
chore(extension-cipherstash): scaffold workspace package shell
wmadden 2052b97
feat(extension-cipherstash): author contract space (T3.1, T3.2, T3.3)
wmadden b5cc7e4
docs(extension-contract-spaces): mark T3.1 + T3.2 + T3.3 completed (M…
wmadden 1f85432
feat(extension-cipherstash): vendor real EQL bundle (eql-2.2.1)
wmadden efbd88f
feat(extension-cipherstash): wire cipherstash:string@1 codec lifecycl…
wmadden 955bbe7
test(extension-cipherstash): pin databaseDependencies absence at thre…
wmadden c77df69
test(extension-cipherstash): pin AM11 + AM12 against the cipherstash …
wmadden 8b21567
docs(extension-contract-spaces): mark T3.4 + T3.5 completed (M3 R2)
wmadden 3e9add6
fix(extension-cipherstash): resolve structural-ops/EQL-bundle CREATE …
wmadden 2562215
feat(migration-tools): include additive ops with invariantIds in deri…
wmadden 6ef575e
feat(extension-cipherstash): add expandNativeType identity hook to st…
wmadden 611b43a
test(extension-cipherstash): T3.6 Scenario A e2e against PGlite
wmadden a00dcc1
docs(extension-contract-spaces): mark T3.6 partial complete (M3 R3)
wmadden 88083b1
fix(extension-cipherstash): sync EQL_V2 ORE composites + state enum v…
wmadden 84abd79
feat(migration-tools): extract materialiseExtensionMigrationPackageIf…
wmadden d210afc
test(extension-cipherstash): T3.7 Scenario C bump-diff (pure-fixture,…
wmadden 3bf05d2
docs(extension-contract-spaces): fold M3 framework-mechanism amendmen…
wmadden 44b4846
docs(extension-contract-spaces): fold M3 cipherstash sub-spec amendme…
wmadden 3f69dfd
docs(extension-contract-spaces): mark M3 R4 tasks complete in plan (T…
wmadden 4c1460f
fix(rebase): adopt M2.5/M2.5b conventions on M3 (cipherstash)
wmadden 9cac5e3
fix(rebase): drop stale extension-test-contract-space workspace deps
wmadden cc67477
chore(rebase): refresh lockfile after dropping stale workspace deps
wmadden 4aa2789
fix(rebase): import canonical control types from framework-components…
wmadden a076733
fix(rebase): cipherstash test typecheck after M2.5 renames
wmadden 7162854
test(cipherstash): migrate to M2.5 aggregate APIs (executeDbInit + he…
wmadden d874663
chore(cipherstash): declare Apache-2.0 license
wmadden ef034ba
test(integration): align F23 fixture with deriveProvidedInvariants on…
wmadden 725650b
fix(migration): check isDirectory() to skip only existing dirs, not a…
wmadden 3a05156
fix(migration): guard readInvariantId against prototype-inherited inv…
wmadden 96a17d4
test(integration): also assert warn count is 0 in aggregate-schema ve…
wmadden c332917
fix(cipherstash): remove redundant main/module/types fields from pack…
wmadden 3de8f7c
fix(cipherstash): use base tsconfig outDir (dist-tsc) instead of dist
wmadden e3417ad
fix(cipherstash): narrow createDomain/createOreComposite param types;…
wmadden 2d8cd32
docs(cipherstash): remove transient projects/ links from README
wmadden 7d4f338
refactor(cipherstash): remove transient spec refs; fail fast on impos…
wmadden c5b947b
docs(cipherstash): remove transient spec/milestone refs from control.ts
wmadden b3fc7dd
fix(cipherstash): align synthetic bundle schema with contract IR (id …
wmadden 63bb076
docs(cipherstash): remove transient spec refs from migrations.ts docb…
wmadden 4497e46
style(cipherstash): split long throw Error lines to satisfy biome for…
wmadden f43d2a7
docs(migration): remove @see projects/ links from deriveProvidedInvar…
wmadden ace08f6
docs(cipherstash): remove AM11/AM12 milestone labels from test header…
wmadden ade8910
docs(cipherstash): remove transient spec/milestone refs from scenario…
wmadden d5da911
docs(cipherstash): update README to reflect codec lifecycle hook is w…
wmadden File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
...ework/3-tooling/migration/test/materialise-extension-migration-package-if-missing.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import { mkdtemp, readFile, rm } from 'node:fs/promises'; | ||
| import { tmpdir } from 'node:os'; | ||
| import { join } from 'pathe'; | ||
| import { afterEach, beforeEach, describe, expect, it } from 'vitest'; | ||
| import { materialiseExtensionMigrationPackageIfMissing } from '../src/io'; | ||
| import { createTestMetadata, createTestOps } from './fixtures'; | ||
|
|
||
| describe('materialiseExtensionMigrationPackageIfMissing', () => { | ||
| let tmpDir: string; | ||
|
|
||
| beforeEach(async () => { | ||
| tmpDir = await mkdtemp(join(tmpdir(), 'materialise-if-missing-')); | ||
| }); | ||
|
|
||
| afterEach(async () => { | ||
| await rm(tmpDir, { recursive: true, force: true }); | ||
| }); | ||
|
|
||
| it('writes the package and returns { written: true } on first run', async () => { | ||
| const ops = createTestOps(); | ||
| const metadata = createTestMetadata({}, ops); | ||
| const pkg = { dirName: 'baseline', metadata, ops }; | ||
|
|
||
| const result = await materialiseExtensionMigrationPackageIfMissing(tmpDir, pkg); | ||
|
|
||
| expect(result.written).toBe(true); | ||
| const manifest = await readFile(join(tmpDir, pkg.dirName, 'migration.json'), 'utf-8'); | ||
| expect(manifest).toContain(metadata.migrationHash); | ||
| }); | ||
|
|
||
| it('returns { written: false } when <targetDir>/<pkg.dirName>/ already exists', async () => { | ||
| const ops = createTestOps(); | ||
| const metadata = createTestMetadata({}, ops); | ||
| const pkg = { dirName: 'baseline', metadata, ops }; | ||
|
|
||
| await materialiseExtensionMigrationPackageIfMissing(tmpDir, pkg); | ||
| const second = await materialiseExtensionMigrationPackageIfMissing(tmpDir, pkg); | ||
|
|
||
| expect(second.written).toBe(false); | ||
| }); | ||
|
|
||
| it('leaves on-disk content byte-identical when the dir already exists (AC-7 / AM12)', async () => { | ||
| const ops = createTestOps(); | ||
| const metadata = createTestMetadata({}, ops); | ||
| const pkg = { dirName: 'baseline', metadata, ops }; | ||
|
|
||
| await materialiseExtensionMigrationPackageIfMissing(tmpDir, pkg); | ||
|
|
||
| const before = await Promise.all( | ||
| ['migration.json', 'ops.json', 'contract.json'].map((name) => | ||
| readFile(join(tmpDir, pkg.dirName, name), 'utf-8'), | ||
| ), | ||
| ); | ||
|
|
||
| await materialiseExtensionMigrationPackageIfMissing(tmpDir, pkg); | ||
|
|
||
| const after = await Promise.all( | ||
| ['migration.json', 'ops.json', 'contract.json'].map((name) => | ||
| readFile(join(tmpDir, pkg.dirName, name), 'utf-8'), | ||
| ), | ||
| ); | ||
|
|
||
| expect(after).toEqual(before); | ||
| }); | ||
|
|
||
| it('creates the parent target directory if it does not yet exist', async () => { | ||
| const nested = join(tmpDir, 'cipherstash'); | ||
| const pkg = { | ||
| dirName: 'baseline', | ||
| metadata: createTestMetadata({}, []), | ||
| ops: [], | ||
| }; | ||
|
|
||
| const result = await materialiseExtensionMigrationPackageIfMissing(nested, pkg); | ||
|
|
||
| expect(result.written).toBe(true); | ||
| const manifest = await readFile(join(nested, pkg.dirName, 'migration.json'), 'utf-8'); | ||
| expect(manifest).toBeDefined(); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # @prisma-next/extension-cipherstash | ||
|
|
||
| [CipherStash](https://cipherstash.com) extension for Prisma Next: searchable | ||
| application-layer encryption for Postgres via the EQL bundle. | ||
|
|
||
| ## Status | ||
|
|
||
| Work in progress. This package documents the current supported behavior only. | ||
|
|
||
| This package authors CipherStash's database scaffolding (the | ||
| `eql_v2_configuration` table, the `eql_v2_encrypted` / `ore_*` composite | ||
| types, the `eql_v2.bloom_filter` / `hmac_256` / `blake3` domains, and the | ||
| EQL bundle SQL) as a **contract space** so the Prisma Next framework can | ||
| plan, apply, and verify it the same way it manages an application's own | ||
| schema. | ||
|
|
||
| The `searchable: true` codec lifecycle hook (`add_search_config` / | ||
| `remove_search_config` ops) is wired up — see `src/exports/control.ts`. The | ||
| codec runtime (encoding/decoding `Encrypted<string>` payloads at query time) | ||
| is not yet implemented. | ||
|
|
||
| ## What this package contributes | ||
|
|
||
| - `contractSpace.contractJson` — the typed objects EQL exposes that user | ||
| columns can name as `nativeType`. Per the IR vocabulary boundary, | ||
| this carries tables / enums / composite types / domains only; functions / | ||
| operators / casts / op classes live below the boundary as opaque DDL inside | ||
| the `installEqlBundle` migration op. | ||
| - `contractSpace.migrations` — the baseline migration that installs the | ||
| vendored EQL bundle SQL (one `cipherstash:install-eql-bundle-v1` op | ||
| carrying the bundle byte-for-byte) plus the structural ops that create | ||
| the typed objects above. Each op carries a `cipherstash:*` invariantId. | ||
| - `contractSpace.headRef` — `(hash, invariants)` describing the current | ||
| target state of the contract space. The framework consumes this at | ||
| `migrate` time to materialise pinned per-space artefacts under | ||
| `migrations/cipherstash/` in the user's repo. | ||
|
|
||
| ## Usage (preview) | ||
|
|
||
| ```ts | ||
| import { defineConfig } from 'prisma-next'; | ||
| import cipherstash from '@prisma-next/extension-cipherstash/control'; | ||
|
|
||
| export default defineConfig({ | ||
| extensionPacks: [cipherstash], | ||
| }); | ||
| ``` | ||
|
|
||
| After `prisma-next migrate`, the user's repo gains | ||
| `migrations/cipherstash/contract.json`, | ||
| `migrations/cipherstash/contract.d.ts`, | ||
| `migrations/cipherstash/refs/head.json`, and | ||
| `migrations/cipherstash/<name>/` migration directories. `db apply` then | ||
| runs CipherStash's migrations against the live database in the same | ||
| transaction as any application-space migration emitted in the same | ||
| `migrate` invocation. | ||
|
|
||
| ## See also | ||
|
|
||
| - Reference fixture: [`packages/3-extensions/test-contract-space`](../test-contract-space) | ||
| - Reference shape: [`packages/3-extensions/pgvector`](../pgvector) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", | ||
| "extends": "//" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| { | ||
| "name": "@prisma-next/extension-cipherstash", | ||
| "version": "0.0.1", | ||
| "license": "Apache-2.0", | ||
| "type": "module", | ||
| "sideEffects": false, | ||
| "description": "CipherStash EQL extension for Prisma Next: contract-space authoring of the encrypted-column scaffolding (eql_v2_configuration table, eql_v2_encrypted/ore_* composite types, eql_v2 domains) plus a baseline migration that installs the vendored EQL bundle SQL byte-for-byte.", | ||
| "scripts": { | ||
| "build": "tsdown", | ||
| "test": "vitest run", | ||
| "test:coverage": "vitest run --coverage", | ||
| "typecheck": "tsc --project tsconfig.json --noEmit", | ||
| "lint": "biome check . --error-on-warnings", | ||
| "lint:fix": "biome check --write .", | ||
| "lint:fix:unsafe": "biome check --write --unsafe .", | ||
| "clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output" | ||
| }, | ||
| "dependencies": { | ||
| "@prisma-next/contract": "workspace:*", | ||
| "@prisma-next/family-sql": "workspace:*", | ||
| "@prisma-next/framework-components": "workspace:*", | ||
| "@prisma-next/migration-tools": "workspace:*", | ||
| "@prisma-next/sql-contract": "workspace:*" | ||
| }, | ||
| "devDependencies": { | ||
| "@prisma-next/adapter-postgres": "workspace:*", | ||
| "@prisma-next/cli": "workspace:*", | ||
| "@prisma-next/driver-postgres": "workspace:*", | ||
| "@prisma-next/sql-schema-ir": "workspace:*", | ||
| "@prisma-next/target-postgres": "workspace:*", | ||
| "@prisma-next/test-utils": "workspace:*", | ||
| "@prisma-next/tsconfig": "workspace:*", | ||
| "@prisma-next/tsdown": "workspace:*", | ||
| "tsdown": "catalog:", | ||
| "typescript": "catalog:", | ||
| "vitest": "catalog:" | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "src" | ||
| ], | ||
| "exports": { | ||
| "./control": "./dist/control.mjs", | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/prisma/prisma-next.git", | ||
| "directory": "packages/3-extensions/cipherstash" | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.