feat(prisma-next): source EQL v3 install SQL from @cipherstash/eql at runtime#694
Conversation
… runtime Baking the ~1.7 MB install bundle into the v3 baseline migration's ops.json coupled every @cipherstash/eql upgrade to a prisma-next release: a patch or minor bump meant re-emitting the migration and cutting a new adapter version. Now @cipherstash/eql is a runtime dependency (^3.0.0). The committed v3 baseline op carries a sentinel placeholder; the descriptor (control.ts) injects readInstallSql() from the installed @cipherstash/eql at build time via withRuntimeEqlSql(). A patch/minor now flows through npm resolution with no re-emit and no adapter release — mirroring how the stash CLI already sources v3 SQL (#692). Safe because the v3 baseline is an invariant-only self-edge (from === to): the install SQL never contributes to the contract-space hash, and contractSpaceFromJson passes ops through with no integrity check on their contents (verifyMigrationHash runs only on the disk read path for the user's repo, never on the in-memory extension descriptor). The apply planner routes on the cipherstash:install-eql-v3-bundle-v1 invariant, not SQL content. ops.json drops from 1,717,297 → 1,219 bytes. No user-facing change — EQL still installs via `prisma-next migration apply`. 600 tests green; build + biome clean. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
🦋 Changeset detectedLatest commit: 01f1d15 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📝 WalkthroughWalkthroughThe EQL v3 baseline migration now stores a sentinel instead of install SQL. Prisma-next injects ChangesEQL runtime SQL sourcing
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant BaselineMigration
participant CipherstashDescriptor
participant EqlBundleV3
BaselineMigration->>CipherstashDescriptor: provide sentinel install operation
CipherstashDescriptor->>EqlBundleV3: build runtime migration package
EqlBundleV3->>EqlBundleV3: readInstallSql()
EqlBundleV3-->>CipherstashDescriptor: return injected SQL and recomputed hash
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/prisma-next/test/v3/migration-v3.test.ts`:
- Around line 44-56: Remove the duplicate readonly execute property from the
type assertion used by the test at
packages/prisma-next/test/v3/migration-v3.test.ts lines 44-56. Apply the same
removal to the assertion at lines 58-71, leaving one execute declaration per
assertion so typechecking succeeds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4ac99242-8cb2-42fc-867f-02ffd2f9fed0
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
.changeset/prisma-next-eql-runtime-source.mdpackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.jsonpackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/migration.tspackages/prisma-next/migrations/20260601T0100_install_eql_v3_bundle/ops.jsonpackages/prisma-next/package.jsonpackages/prisma-next/src/exports/control.tspackages/prisma-next/src/migration/eql-bundle-v3.tspackages/prisma-next/test/v3/migration-v3.test.ts
…ast injection Code-review follow-ups on the runtime EQL-SQL sourcing: - Pin @cipherstash/eql exact (3.0.0), not ^3.0.0. prisma-next's v3 domain TYPES come from @cipherstash/stack (which encodes them against a specific EQL release); floating the install SQL via a caret would let the applied schema drift from the pinned type surface, and diverge from the exact pins in @cipherstash/stack and the stash CLI (both install into the same DB). Exact keeps types and SQL coherent and still removes the 1.7 MB re-emit coupling — the actual win. Reframed the "flows through" wording to "no re-emit" throughout. - withRuntimeEqlSql now matches the placeholder by its SENTINEL value (not an op id) and THROWS if no placeholder is present. Matching an op id required three hardcoded copies to agree; a drift silently applied the inert sentinel comment as the "install" (empty EQL, caught only by an indirect postcheck, or not at all when postchecks are disabled). Sentinel-match is immune to op-id drift and fails loudly at descriptor build. Dropped the V3_INSTALL_OP_ID const. - The SQL read is wrapped (readV3InstallSql) with an actionable error, since it now runs at control.ts import for every control-plane consumer (was a raw readFileSync throw). Mirrors the CLI's guard. - Non-lossy swap: only the sentinel step's `sql` is rewritten; sibling execute steps and extra fields are preserved. Added a drift-guard + non-lossy test. 601 tests green; build + biome + frozen-lockfile clean. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
…ace (typecheck) The prior commit removed `readInstallSql` from eql-bundle-v3's re-export, but the live-test helpers (`test/live/helpers/eql-v3.ts`, `migration-apply-live-pg.test.ts`) import it from there — a TS2459 the vitest run misses (live suites are skipped) but the `typecheck` CI step catches. Re-export it. Also non-null-guard `contractSpace` in the new descriptor-injection test (`contractSpace!`), matching descriptor.test.ts. typecheck exits 0; 601 tests green. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
Differential Review: PR 694Codex/gpt-5.6-sol Executive Summary
Overall Risk: HIGH Key Metrics:
What ChangedCommit Range:
Critical Findings🟠 HIGH: Freshly seeded migrations fail their content-addressed integrity checkFile: Description:
Observed values: Historical Context:
Failure Scenario:
Proof of Concept: const pkg = descriptor.contractSpace.migrations[1]
await materialiseMigrationPackage(root, pkg)
await readMigrationPackage(join(root, pkg.dirName))
// MigrationToolsError: MIGRATION.HASH_MISMATCHThe repository's Prisma example E2E does not expose this because its migration directory already contains the old baked package; the seed phase skips existing directories by design. Recommendation: Build the runtime migration package atomically: inject the SQL and recompute 🟡 MEDIUM: The credentialed live migration test still asserts the removed baked-SQL modelFile: Description: The test reads committed Recommendation: Read the operation from the injected descriptor (or, preferably, from the materialized-and-verified package used by the real CLI path), then apply and compare that SQL. Update the stale comments and test name. Test Coverage AnalysisLocal results:
The highest-value invariant test is a round trip: descriptor package → materialize → verified read. That property is currently absent. Blast Radius Analysis
The repository contains three direct consumers of Historical ContextNo authorization, crypto primitive, plaintext-logging, or payload-shape guard was removed. The relevant removed behavior was content identity: commit The exact RecommendationsImmediate (Blocking)
Before Production
Technical Debt
Analysis MethodologyStrategy: SURGICAL (751 relevant source/config files; 9 changed files) Coverage:
Limitations:
Confidence: HIGH Appendix: Commit References
|
|
Addressed the review findings in
Validation:
|
|
Comprehensive human and AI review (Coderabbit and Codex/gpt-5.6-sol) |
Why
Baking the ~1.7 MB EQL v3 install bundle into the v3 baseline migration's
ops.jsonmeant every@cipherstash/eqlupgrade required re-running the maintainer emit loop and committing another generated SQL blob. This is the concrete cost @coderdan flagged.This is the "depend, don't bake" direction from #690 (PR3), scoped to what actually matters: the sourcing model. It does not change the contract-space head-ref/invariants or require framework-migration-emitter changes, because the SQL is not part of the contract storage hash.
What changed
@cipherstash/eqlis now an exact-pinned runtime dependency (3.0.0, previously a devDependency), matching the EQL version used by@cipherstash/stackand thestashCLI.control.tsuseswithRuntimeEqlSqlPackage()to injectreadInstallSql()from the installed@cipherstash/eqland recompute the migration hash from the resulting operations.ops.json: 1,717,297 → 1,219 bytes.Why it's safe (no framework surgery)
The v3 baseline is an invariant-only self-edge (
from === to; the bundle declares no contract-space storage). Therefore:migrationHashfrom the injected operations before Prisma Next materializes the package;cipherstash:install-eql-v3-bundle-v1invariant, not SQL content.Verified against
@prisma-next/migration-tools@0.14.0.Trusted SQL bundle insertion (not user-input SQL injection)
Here, “inject” means inserting a trusted package asset into the migration descriptor. It is not a path for arbitrary or user-provided SQL:
@cipherstash/eql@3.0.0; no user input is interpolated.sqlfield is replaced; sibling steps and migration fields are preserved.The trust chain is: exact-pinned package → trusted static SQL asset → exact sentinel replacement → recomputed content hash → verified disk round trip.
This does not sanitize arbitrary SQL or make user-generated raw SQL safe; it prevents untrusted input from entering this path.
User-facing impact
None. EQL still installs as part of
prisma-next migration apply. The v2 baseline is untouched (still baked; v2 is legacy/unreleased).Tests
ops.jsoncarries the sentinel and remains under 5 KB.readInstallSql()and recomputes the runtime migration hash.code:checkpass.For @calvinbrewer
This changes the v3 baseline authoring model:
migration.tsemits a placeholder, while the runtime descriptor injects the SQL and recomputes the content-addressed migration hash. The re-emit loop (pnpm exec tsx migrations/.../migration.ts) still works and is a deterministic no-op. Flagging since it touches the contract-space baseline you own—the invariant/head-ref wiring is unchanged.Part of #690 (the "depend on @cipherstash/eql, don't bake" thread).
https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
Summary by CodeRabbit
@cipherstash/eqlis now a runtime dependency to stay aligned with v3 domain expectations.