Skip to content

Add World.getEncryptionKeyForRun and thread encryption key through serialization#979

Open
TooTallNate wants to merge 2 commits intonate/async-serdefrom
nate/encryptor-interface
Open

Add World.getEncryptionKeyForRun and thread encryption key through serialization#979
TooTallNate wants to merge 2 commits intonate/async-serdefrom
nate/encryptor-interface

Conversation

@TooTallNate
Copy link
Member

@TooTallNate TooTallNate commented Feb 8, 2026

Summary

  • Adds World.getEncryptionKeyForRun(run) returning Uint8Array | undefined as the interface for retrieving per-run encryption keys
  • Updates all 8 dehydrate/hydrate serialization functions to accept key: Uint8Array | undefined
  • Updates runtime callers, CLI, and tests to thread the key parameter through

@github-actions
Copy link
Contributor

github-actions bot commented Feb 8, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 405 0 36 441
✅ 💻 Local Development 520 0 68 588
✅ 📦 Local Production 336 0 56 392
✅ 🐘 Local Postgres 336 0 56 392
✅ 🪟 Windows 46 0 3 49
❌ 🌍 Community Worlds 105 42 9 156
✅ 📋 Other 126 0 21 147
Total 1874 42 249 2165

❌ Failed Tests

🌍 Community Worlds (42 failed)

turso (42 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling retry behavior workflow completes despite transient 5xx on step_completed
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 45 0 4
✅ example 45 0 4
✅ express 45 0 4
✅ fastify 45 0 4
✅ hono 45 0 4
✅ nitro 45 0 4
✅ nuxt 45 0 4
✅ sveltekit 45 0 4
✅ vite 45 0 4
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 42 0 7
✅ express-stable 42 0 7
✅ fastify-stable 42 0 7
✅ hono-stable 42 0 7
✅ nextjs-turbopack-canary 46 0 3
✅ nextjs-turbopack-stable 46 0 3
✅ nextjs-webpack-canary 46 0 3
✅ nextjs-webpack-stable 46 0 3
✅ nitro-stable 42 0 7
✅ nuxt-stable 42 0 7
✅ sveltekit-stable 42 0 7
✅ vite-stable 42 0 7
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 42 0 7
✅ express-stable 42 0 7
✅ fastify-stable 42 0 7
✅ hono-stable 42 0 7
✅ nitro-stable 42 0 7
✅ nuxt-stable 42 0 7
✅ sveltekit-stable 42 0 7
✅ vite-stable 42 0 7
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 42 0 7
✅ express-stable 42 0 7
✅ fastify-stable 42 0 7
✅ hono-stable 42 0 7
✅ nitro-stable 42 0 7
✅ nuxt-stable 42 0 7
✅ sveltekit-stable 42 0 7
✅ vite-stable 42 0 7
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 46 0 3
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
✅ mongodb 46 0 3
✅ redis-dev 3 0 0
✅ redis 46 0 3
✅ turso-dev 3 0 0
❌ turso 4 42 3
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 42 0 7
✅ e2e-local-postgres-nest-stable 42 0 7
✅ e2e-local-prod-nest-stable 42 0 7

📋 View full workflow run


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: success
  • Local Prod: failure
  • Local Postgres: failure
  • Windows: success

Check the workflow run for details.

@vercel
Copy link
Contributor

vercel bot commented Feb 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Error Error Feb 15, 2026 0:57am
example-nextjs-workflow-webpack Error Error Feb 15, 2026 0:57am
example-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-astro-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-express-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-fastify-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-hono-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-nitro-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-nuxt-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-sveltekit-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workbench-vite-workflow Ready Ready Preview, Comment Feb 15, 2026 0:57am
workflow-docs Ready Ready Preview, Comment, Open in v0 Feb 15, 2026 0:57am
workflow-nest Ready Ready Preview, Comment Feb 15, 2026 0:57am
workflow-swc-playground Ready Ready Preview, Comment Feb 15, 2026 0:57am

@changeset-bot
Copy link

changeset-bot bot commented Feb 8, 2026

🦋 Changeset detected

Latest commit: 9c7b912

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@workflow/core Patch
@workflow/world Patch
@workflow/cli Patch
@workflow/world-testing Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
workflow Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-vercel Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

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

Copy link
Member Author

TooTallNate commented Feb 8, 2026

Copy link
Collaborator

@pranaygp pranaygp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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: Encryptor has all-optional methods, so existing World implementations don't break
  • EncryptionContext is minimal (just runId) -- good for forward compatibility
  • KeyMaterial interface for o11y tooling is a thoughtful addition
  • The getEncryptorForRun() method on World is 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:

  1. resolveEncryptorForRun type safety: In resume-hook.ts line 29-31, getEncryptorForRun is accessed via (world as any).getEncryptorForRun. Since World already extends Encryptor and getEncryptorForRun is defined on World, you should be able to use optional chaining directly: world.getEncryptorForRun?.(runId). The 'getEncryptorForRun' in world + as any pattern bypasses type checking unnecessarily.

  2. Serialization parameter ordering: The PR reorders parameters in the dehydrate/hydrate functions. For example, dehydrateWorkflowArguments goes 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.

  3. _encryptor unused parameter pattern: All 8 functions have _encryptor: Encryptor that 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.

  4. hydrateResourceIO now requires encryptor: In observability.ts, hydrateResourceIO now takes an Encryptor parameter, and all callers pass world. 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.

@TooTallNate TooTallNate marked this pull request as ready for review February 9, 2026 23:12
Copilot AI review requested due to automatic review settings February 9, 2026 23:12
@TooTallNate TooTallNate changed the title Add Encryptor interface and thread through serialization layer Add World.getEncryptionKeyForRun and thread encryption key through serialization Feb 14, 2026
@TooTallNate TooTallNate force-pushed the nate/encryptor-interface branch from 6594710 to 9c7b912 Compare February 15, 2026 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants