runInSandbox executes command batches under policy and budget controls, stages
explicit input files, and extracts caller-requested artifacts after command
completion.
The default Vercel Sandbox runtime is node24. Callers may explicitly request
node22 or python3.13 when a review workload requires a different runtime.
Executions set persistent: false, so stopping a review discards its filesystem
instead of creating a persistent snapshot.
commandAllowlist: Set<string>networkProfile: 'deny_all' | 'bootstrap_then_deny' | 'allowlist_only'allowlistDomains: string[]envAllowlist: Set<string>budget:maxWallTimeMsmaxCommandTimeoutMsmaxCommandCountmaxOutputBytesmaxArtifactBytes
Default policy (createDefaultPolicy) denies network, uses fixed command allowlist, and enforces conservative execution budgets.
- Commands are schema-validated before execution.
- Commands outside allowlist are rejected.
- Command names must be executable names, not paths; staged scripts must be
invoked through an allowlisted runtime such as
node. - Per-command timeouts are clamped by policy max and enforced through the
Sandbox SDK's native
timeoutMscommand option. - Output size accumulation is enforced across run.
- Wall-time budget is enforced across run.
- Selected secret patterns in stdout/stderr are redacted.
- For
bootstrap_then_deny, commands may opt intophase: 'bootstrap'; network is switched to deny-all before the first runtime command and again after all bootstrap-only batches. - Requested artifact files are read back through the sandbox filesystem API, redacted, and included in the returned execution output.
- Structured audit metadata is returned:
- policy profile and allowlist sizes
- consumed budgets (command count, wall time, output bytes, artifact bytes)
- redaction counters
- per-command timing/output/redaction records
maxArtifactBytesis enforced on extracted artifact content.- A caller-provided
AbortSignalis forwarded to the Sandbox SDK's native command and operation APIs. Sandbox creation, file staging, network-policy updates, command output reads, and artifact extraction receive the caller signal when the SDK supports it. Aborted calls still stop the sandbox infinallywith a separate bounded cleanup signal before surfacing the abort error to the caller.
remoteSandbox is supported only through detached delivery. Inline HTTP
requests return 400 with executionMode "remoteSandbox" requires detached delivery because the sandbox runner is owned by review-worker.
Detached remote sandbox flow:
review-servicevalidates the request, persists a queued record, and startsreview-worker.review-corerejects git-backed remote sandbox targets before host Git access. The current safe path accepts onlycustomtargets and prepares an empty diff context until sandbox source binding is implemented.review-workerstages a bounded review input JSON and a fixedreview-runner.mjsinto Vercel Sandbox.- The worker runs exactly one
node review-runner.mjscommand under deny-all network withCIas the only allowed environment key. - The worker extracts
review-output.json, parses it as provider-shaped output, and returnssandboxAuditwith the SDK's unique sandbox name assandboxId, plus policy, budgets, redaction counters, and command audit records. review-servicepersists the resultingsandboxId; lifecycle event correlation also includessandboxIdwhen available.
The current sandbox runner is intentionally policy-only: it proves remote execution, artifact extraction, and audit propagation without injecting provider tokens or running arbitrary package-manager commands in the microVM. Provider execution and git-backed target review inside Vercel Sandbox remain gated on later hosted auth/source-binding work.
Package tests use deterministic SDK fakes. Credential-backed verification of the Vercel control plane requires a linked project and Vercel OIDC or access token, and remains an operator-run release check rather than a CI unit test.
Detached runs are started via ReviewWorker.startDetached(requestInput).
Execution strategy:
- Atomically reserve the queued service record and service-owned runtime lease
through
ReviewStoreAdapter. - Use the lease for queue/concurrency backpressure and stale-run detection.
- Start
@workflow/core/runtimewithstart(reviewWorkflow, [request]). - Persist
detachedRunId,workflowRunId, and queued acceptance without an immediate Workflow status read; status is reconciled through latergetRun(runId)lookups. - If Workflow cannot accept the run, persist a failed terminal record and return an error instead of falling back to in-process success.
reviewWorkflow routes provider-backed requests to a step with Workflow retries
disabled because provider policy owns model and network attempts. It routes
remoteSandbox requests to a separate step capped at three Workflow retries for
transient sandbox operational failures.
Run records expose:
runIdstatus(queued|running|completed|failed|cancelled)- timestamps
- optional
error - optional
result - optional
workflowRunId - optional
sandboxId - optional runtime
lease - optional
cancelRequestedAt
ReviewWorker.get resolves current status directly from Workflow by run ID and
captures completed/failure outcomes. Service routes then persist the latest
snapshot, lifecycle events, artifact metadata, and retention state through the
durable store.
ReviewWorker.cancel checks Workflow status by run ID, skips terminal runs, and
delegates cancellation to Workflow. When the target step is active in the same
worker process, the worker also aborts the local AbortController passed into
runReview, providers, and sandbox execution. Cross-process cancellation still
uses Workflow status as the durable authority. The service persists
cancelRequestedAt, keeps the lease while cancellation is pending, and persists
cancelled plus replayable lifecycle events only after Workflow reports
cancelled. If Workflow accepts cancellation but has not reported a terminal
cancelled state, the API returns 202 with cancelled: false. If Workflow
reports terminal state first or cancellation is not possible, the API returns
409 and leaves the observed terminal state as the durable service status.
ConvexMetadataBridge is optional and enabled only when CONVEX_URL is set.
On completion, core may call mirrorWrite(reviewId, result) with payload:
reviewIdprovidermodelfindingsCountoverallCorrectnesssummarycompletedAt
Bridge failures are intentionally non-blocking and logged as warnings.