monad-developers / monad-developers/ultrafuzz

Modal worker persists descriptor-rooted workflow path outside relocated handoff

Open
#713 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

deferred-post-v0.1
Dominant language
TypeScript
Stars
85
Forks
18
Avg merge
11h 10m
Merged PRs (30d)
194

Description

Summary

The release Modal node worker uses a child-visible descriptor path for safely loading the sealed workflow, but also exports that /proc/<pid>/fd/<n>/... path as the persisted workflow identity. The generated relocated workflow requires its persisted path to remain inside the cloud handoff project, so the first cloud node fails before inference.

Generic reproduction

  1. At release commit 9b0bc8cab2e681bbffeee385c1f80f85a47087d3, configure any generic external Solidity project to use the default topology with Modal cloud execution.
  2. Start the campaign and let the first cloud node reach runDurableWorkflow.
  3. Observe that packages/modal/src/node-worker.ts constructs a child-visible workflow load path under /proc/<worker-pid>/fd/<n>/... and assigns that same value to ULTRAFUZZ_WORKFLOW_PERSISTED_PATH.
  4. The generated workflow evaluates the persisted path relative to the relocated handoff root and rejects it.

Observed error:

cloud worker phase resume-workflow failed with code 1
cli load workflow: persisted workflow path must stay inside the cloud handoff project

A target-free path reproduction is:

import fs from "node:fs";
import os from "node:os";
import path from "node:path";

const root = fs.mkdtempSync(path.join(os.tmpdir(), "uf-modal-path-"));
const snapshot = path.join(root, "snapshot");
const workflow = path.join(snapshot, ".smithers", "workflows", "generic.tsx");
fs.mkdirSync(path.dirname(workflow), { recursive: true });
fs.writeFileSync(workflow, "export default {};\n");
const fd = fs.openSync(snapshot, fs.constants.O_RDONLY | fs.constants.O_DIRECTORY);
const descriptorWorkflow = `/proc/${process.pid}/fd/${fd}/.smithers/workflows/generic.tsx`;

// Safe to execute: both names resolve to the same sealed file.
if (fs.realpathSync(descriptorWorkflow) !== fs.realpathSync(workflow)) throw new Error("identity mismatch");

// Invalid as a durable identity: the descriptor name is outside the handoff root.
const relative = path.relative(root, descriptorWorkflow);
if (!(relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) throw new Error("expected rejection");

Expected behavior

Keep the CLI workflow argument descriptor-anchored for safe execution, while exporting the already verified canonical workflow path inside the handoff project as ULTRAFUZZ_WORKFLOW_PERSISTED_PATH.

Actual behavior

The descriptor-rooted load path is also treated as the persisted identity, making the relocated cloud workflow reject it before any model work starts.

Suggested focused regression

The existing runDurableWorkflow test should continue to assert that the CLI workflow argument is /proc/<pid>/fd/<n>/..., but should assert that ULTRAFUZZ_WORKFLOW_PERSISTED_PATH equals the canonical workflow path under the fixture project root.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/modal/src/node-worker.ts and inspect how runDurableWorkflow constructs the descriptor-anchored CLI workflow argument and sets ULTRAFUZZ_WORKFLOW_PERSISTED_PATH. Run the existing runDurableWorkflow test and extend it so the CLI argument remains descriptor-based while the persisted path is the canonical workflow path under the fixture project root. Done means the focused regression passes and the relocated cloud workflow no longer rejects its persisted identity.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.