Skip to content

Enforce preview URL runtime activation#708

Draft
ghostwriternr wants to merge 4 commits into
mainfrom
preview-stack-v2/01-preview-runtime-activation
Draft

Enforce preview URL runtime activation#708
ghostwriternr wants to merge 4 commits into
mainfrom
preview-stack-v2/01-preview-runtime-activation

Conversation

@ghostwriternr
Copy link
Copy Markdown
Member

@ghostwriternr ghostwriternr commented May 19, 2026

Preview URLs currently mix two different concepts: persistent token authorization and live container runtime state. A preview URL token can survive container restart, but the user process serving that port does not. That means an old preview URL can start the container or reach a later container instance that never called exposePort() for that port.

This change separates token validity from current-runtime activation.

In this stack, “current runtime” means the currently running container instance/generation. A preview URL is active only if exposePort() was called for that port in that current container runtime.

portTokens remains persistent token authorization: it records whether a preview URL token is valid for a sandbox port across container restarts. That token staying valid does not mean a live process is currently serving the port, or that the URL may forward traffic in a later container runtime.

Preview URL traffic now enters the Sandbox Durable Object before forwarding. The Durable Object checks persistent token authorization and current-runtime activation, strips spoofed internal preview headers, then forwards only through Container.fetchIfRunning(), which does not start a stopped container.

Preview state updates use Durable Object storage transactions so concurrent expose/unexpose operations read and write coherent token and activation snapshots.

The response contract becomes:

  • malformed or non-preview hostnames fall through without being handled as preview requests;
  • invalid, revoked, or destroyed tokens return 404 INVALID_TOKEN;
  • valid tokens without current-runtime activation return 410 STALE_PREVIEW_URL;
  • valid tokens with activation also return 410 STALE_PREVIEW_URL if the current container is no longer running and healthy;
  • active preview URLs forward only when the container is already running and healthy.

exposePort() is now the explicit preview action that activates a port for the current runtime. Restarting a service on the same port is not enough to revive an old preview URL; callers must expose the port again.

The desktop preview integration now also goes through exposePort() activation. It can no longer synthesize a URL from a persisted token when current-runtime activation fails.

This PR only adds a runtime identity used to fence preview URL activation. It does not introduce a general lifecycle manager and does not change sessions, processes, interpreters, mounts, or backups.

Preview route parsing details are kept internal rather than exported as public API.

This PR depends on @cloudflare/containers support for Container.fetchIfRunning(). The dependency currently points at the preview package from cloudflare/containers#212 and must be replaced with a published version before this stack can merge.

The changeset is intentionally minor because preview URLs that previously auto-survived restart now return 410 STALE_PREVIEW_URL until the port is exposed again in the new runtime.


This is part 1 of 3 in the preview URL lifecycle stack:

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 19, 2026

🦋 Changeset detected

Latest commit: 105c825

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

This PR includes changesets to release 1 package
Name Type
@cloudflare/sandbox Minor

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 19, 2026

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/sandbox-sdk/@cloudflare/sandbox@708

commit: 105c825

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 19, 2026

🐳 Docker Images Published

Variant Image
Default cloudflare/sandbox:0.0.0-pr-708-105c825
Python cloudflare/sandbox:0.0.0-pr-708-105c825-python
OpenCode cloudflare/sandbox:0.0.0-pr-708-105c825-opencode
Musl cloudflare/sandbox:0.0.0-pr-708-105c825-musl
Desktop cloudflare/sandbox:0.0.0-pr-708-105c825-desktop

Usage:

FROM cloudflare/sandbox:0.0.0-pr-708-105c825

Version: 0.0.0-pr-708-105c825


📦 Standalone Binary

For arbitrary Dockerfiles:

COPY --from=cloudflare/sandbox:0.0.0-pr-708-105c825 /container-server/sandbox /sandbox
ENTRYPOINT ["/sandbox"]

Download via GitHub CLI:

gh run download 26225396088 -n sandbox-binary

Extract from Docker:

docker run --rm cloudflare/sandbox:0.0.0-pr-708-105c825 cat /container-server/sandbox > sandbox && chmod +x sandbox

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 7 additional findings.

Open in Devin Review

@aron-cf
Copy link
Copy Markdown
Contributor

aron-cf commented May 19, 2026

@ghostwriternr can we break the dependency on @cloudflare/containers here and update the code if/when the patch lands upstream.

@ghostwriternr ghostwriternr force-pushed the preview-stack-v2/01-preview-runtime-activation branch from ccfb032 to 61c6d64 Compare May 20, 2026 10:36
The default E2E sandbox app can hit its 50-instance cap when the
three transport jobs run file-parallel Vitest suites. Raise the cap
modestly to match observed CI demand while keeping capacity bounded.
Make lifecycle synchronization wait for terminal container states and keep preview URL tests closer to public SDK flows. This avoids relying on transitional stop states or hand-edited preview hostnames.
Declare warm pool sizing in the test worker config instead of mutating every container app after deploy. This keeps variant images from reserving unused warm capacity during stacked PR CI.
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