Add World.getEncryptionKeyForRun and thread encryption key through serialization#979
Add World.getEncryptionKeyForRun and thread encryption key through serialization#979TooTallNate wants to merge 2 commits intonate/async-serdefrom
Conversation
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests🌍 Community Worlds (42 failed)turso (42 failed):
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
✅ 📋 Other
❌ Some E2E test jobs failed:
Check the workflow run for details. |
🦋 Changeset detectedLatest commit: 9c7b912 The changes in this PR will be included in the next version bump. This PR includes changesets to release 18 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 |
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
pranaygp
left a comment
There was a problem hiding this comment.
Review: PR #979 - Add Encryptor interface and thread through serialization layer
Summary: Adds the Encryptor, EncryptionContext, and KeyMaterial interfaces to @workflow/world, makes World extend Encryptor, and threads the encryptor parameter through all serialization functions. This is a no-op refactor -- the encryptor parameter is unused (_encryptor) throughout.
Strengths:
- Clean interface design:
Encryptorhas all-optional methods, so existingWorldimplementations don't break EncryptionContextis minimal (justrunId) -- good for forward compatibilityKeyMaterialinterface for o11y tooling is a thoughtful addition- The
getEncryptorForRun()method onWorldis a well-designed escape hatch for cross-deployment encryption (e.g.,resumeHook()from newer deployment) getHookByTokenWithEncryptor()resolves the encryptor once and reuses it -- avoids redundant key resolution
Concerns:
-
resolveEncryptorForRuntype safety: Inresume-hook.tsline 29-31,getEncryptorForRunis accessed via(world as any).getEncryptorForRun. SinceWorldalready extendsEncryptorandgetEncryptorForRunis defined onWorld, you should be able to use optional chaining directly:world.getEncryptorForRun?.(runId). The'getEncryptorForRun' in world+as anypattern bypasses type checking unnecessarily. -
Serialization parameter ordering: The PR reorders parameters in the dehydrate/hydrate functions. For example,
dehydrateWorkflowArgumentsgoes from(value, ops, runId, ...)to(value, runId, encryptor, ops, ...). This is a breaking change to the internal API. While these aren't public, any external code calling these directly would break. The reorder makes sense semantically (runId + encryptor are conceptually paired), but consider documenting this in the changeset. -
_encryptorunused parameter pattern: All 8 functions have_encryptor: Encryptorthat is unused. This is expected since the actual wiring happens in #957. However, this means if #979 lands but #957 doesn't (or is delayed), there's dead parameter threading throughout the codebase. A minor code smell but acceptable for a PR stack. -
hydrateResourceIOnow requiresencryptor: Inobservability.ts,hydrateResourceIOnow takes anEncryptorparameter, and all callers passworld. This means the observability layer now has a dependency on the World instance. Previously it was a pure data transformation. This is a reasonable tradeoff for encryption support, but worth noting the coupling increase.
Overall, well-structured interface design. The cross-deployment encryption support via getEncryptorForRun shows good foresight for production scenarios.
6594710 to
9c7b912
Compare

Summary
World.getEncryptionKeyForRun(run)returningUint8Array | undefinedas the interface for retrieving per-run encryption keyskey: Uint8Array | undefined