Skip to content

Add per-PR assets on preview.cdn.rrweb.com #1925

Description

@Juice10

Status

PR #1926 implements npm-compatible previews through pkg.pr.new and is the current short-term path. This issue remains open for browser-ready assets on preview.cdn.rrweb.com. Those assets need the separate origin, validation, caching, and cleanup controls described below.

Motivation

Reviewers should be able to load the browser bundles produced by any pull request before it merges. These builds contain untrusted PR JavaScript, so they must use a separate origin. Publishing them on cdn.rrweb.com would let arbitrary PR code inherit the CSP trust that consumers already grant the production CDN.

The production CDN already uses immutable exact-version URLs plus short-lived redirect aliases. The preview CDN can reuse that model per PR.

Proposed design

For PR 123 at commit <full-sha>:

  • Immutable assets: https://preview.cdn.rrweb.com/pr/123/<full-sha>/<asset>
  • Immutable manifest: https://preview.cdn.rrweb.com/pr/123/<full-sha>/manifest.json
  • Mutable alias: https://preview.cdn.rrweb.com/pr/123/latest/<asset>, implemented as a redirect to the immutable URL

The manifest should record the repository, PR number, full commit SHA, workflow run ID, build timestamp, and each allowed file's path, byte size, and SHA-256 hash.

Use two workflows:

  1. An unprivileged pull_request workflow checks out and builds PR code without secrets or write permissions, then uploads an Actions artifact containing only the allowlisted distributable files and manifest.
  2. A trusted workflow_run workflow receives the completed build event and has pull-requests: write plus preview-only R2 credentials. It verifies the source repository/workflow, successful run, run ID, PR association, head SHA, archive paths, allowlist, file count, size limits, and hashes. It must treat every downloaded file as inert bytes: never source, import, evaluate, or execute the artifact or any script from the PR. After validation it uploads to R2 and updates one sticky PR comment with the commit, manifest, immutable URLs, and latest URLs.

Use a dedicated preview R2 bucket and credentials that cannot read, write, purge, or configure production CDN storage. Serve it only from preview.cdn.rrweb.com.

Caching:

  • Immutable paths: Cache-Control: public, max-age=31536000, immutable
  • latest redirects and any mutable metadata: short-lived caching, for example Cache-Control: public, max-age=60
  • Update latest only after every immutable object and the manifest have uploaded and passed hash verification.

Keep builds while a PR is open. A scheduled cleanup should delete the PR prefix 30 days after closure, and an R2 lifecycle rule should remove preview objects older than 90 days as a backstop. Remove or invalidate mutable aliases when their target is deleted.

Acceptance criteria

  • Every PR, including fork PRs, can produce preview assets without exposing secrets to PR code.
  • A trusted uploader validates artifacts but never executes them.
  • Preview assets are unavailable through cdn.rrweb.com and use preview-only R2 credentials.
  • Immutable URLs remain content-stable and their bytes match the manifest SHA-256 hashes.
  • latest resolves to the newest successfully uploaded commit for that PR and is never updated after a failed or partial upload.
  • One sticky PR comment is created or updated with working preview links and the current commit.
  • Cache headers match the immutable and mutable behavior above.
  • Closed PR assets are removed by the cleanup policy, with the R2 lifecycle rule as a backstop.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions