Skip to content

feat(w1 slice-2b/O1): INERT CF Live Output RTMP restream + SSRF-at-connect (wre#287) - #320

Merged
yakimoto merged 2 commits into
mainfrom
feat/w1-o1-ext-rtmp
Jul 23, 2026
Merged

yakimoto merged 2 commits into
mainfrom
feat/w1-o1-ext-rtmp

Conversation

@yakimoto

@yakimoto yakimoto commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Concrete CfStreamEgressClient adapter (egress-cf-stream-live-output-client.ts): calls CF's real POST /accounts/{accountId}/stream/live_inputs/{liveInputId}/outputs with {url, streamKey}, derived live-input uid from the bridged cfstream:{uid} sessionId, fail-closed typed errors (no throw into media path).
  • Closes the "SSRF only at create, not connect" gap: assertDestinationSafeAtConnect (egress-arm.ts) re-runs validateDestinationUrl immediately before any outbound provision/dial.
  • New armExternalRtmpRestream arm path: resolveDestinationForArm -> refuse (404) if null -> SSRF-at-connect -> refuse (403) if unsafe -> provisionOutput.
  • INERT: requires BOTH EGRESS_ROUTER_ENABLED and EGRESS_DEST_MGMT_ENABLED armed (default OFF). No call site wires it in yet — prod byte-identical.
  • Part of Zoom Live Media epic wave-zoom#46. Consumes resolveDestinationForArm from wre#289 (feat(w1): external egress destination mgmt + SSRF guard + key encryption (O3, #17, #18) #316/feat(w1 slice-1b): INERT emitEgressLegUsage egress-leg metering #318, already on main).

Test plan

  • npx tsc --noEmit — 0 errors
  • npx vitest run — 1445/1445 passing (full suite, no regressions)
  • New tests prove: correct CF request shape (mocked fetch), non-2xx CF reply -> typed error, SSRF-at-connect rejects a rebound destination (public IP at create, link-local at connect) with NO provision call, absent/foreign-org destId -> refused with NO provision call, flags-off -> INERT

🤖 Generated with Claude Code


Note

Medium Risk
Touches egress connect-time SSRF and outbound CF provisioning for user-supplied RTMP URLs, but stays inert without both flags and has no production call site yet.

Overview
Adds inert-by-default wiring to simulcast an already-ingested Cloudflare Stream live input to a customer RTMP destination (YouTube/Twitch/custom), gated on both EGRESS_ROUTER_ENABLED and EGRESS_DEST_MGMT_ENABLED. Nothing in prod calls it yet.

egress-arm.ts introduces assertDestinationSafeAtConnect (re-runs validateDestinationUrl right before dial/provision to close DNS-rebind after create-time checks) and armExternalRtmpRestream: resolve org-scoped destination → SSRF-at-connect → typed provisioned / refused outcomes (404/403/CF errors), no throws into the media path.

egress-cf-stream-live-output-client.ts is the concrete CfStreamEgressClient that POSTs CF Stream live outputs: derives live-input id from cfstream:{32-hex} session ids, splits combined RTMP URLs into CF’s {url, streamKey} body, fail-closed on bad input or API errors.

Vitest covers DNS-rebind refusal, flag-off inert behavior, org/destination failures, and mocked CF request shape.

Reviewed by Cursor Bugbot for commit 94e1aae. Configure here.


Summary by cubic

Adds external RTMP restreaming via Cloudflare Stream Live Output and closes the DNS-rebind gap by rechecking destinations at connect time, centralized at the CF-output chokepoint. Inert behind EGRESS_ROUTER_ENABLED and EGRESS_DEST_MGMT_ENABLED. Addresses wre#287 and sec-review #320.

  • New Features

    • CfStreamEgressLiveOutputClient: calls Cloudflare POST /accounts/{accountId}/stream/live_inputs/{liveInputId}/outputs, derives liveInputId from cfstream:{uid}, splits combined rtmp://.../app/streamKey, returns typed errors on non-2xx.
    • assertDestinationSafeAtConnect: re-runs validateDestinationUrl right before provisioning to block DNS-rebinds.
    • armExternalRtmpRestream: resolves the org-scoped destination, rechecks SSRF, then provisions via the client; typed outcomes; INERT unless both flags are on.
  • Bug Fixes

    • Centralized SSRF-at-connect in CfStreamEgressLiveOutputClient.provisionOutput so both passthrough and O1 arm paths cannot provision if the resolved IP is unsafe.
    • Guarded destination kind in armExternalRtmpRestream (non-rtmp refused with 400).
    • Wrapped resolveDestinationForArm in try/catch; failures now refuse with 500 (fail-closed), not throws.

Written for commit 06c4207. Summary will update on new commits.

Review in cubic

…recheck (INERT, wre#287)

What: implements the concrete CfStreamEgressClient adapter
(egress-cf-stream-live-output-client.ts) that turns an already-ingested
Zoom CF Live Input into a live simulcast to a customer's external RTMP
destination via CF's real `POST /accounts/{accountId}/stream/live_inputs/
{liveInputId}/outputs` endpoint, reusing cf-stream-live-client.ts's
account-id + bearer-token auth pattern. Fails closed (typed error, never
throws) on a non-2xx CF reply.

Closes the SSRF-only-at-create gap: adds assertDestinationSafeAtConnect
(egress-arm.ts), which re-runs validateDestinationUrl immediately before
any outbound provision/dial, and wires it into a new
armExternalRtmpRestream arm path: resolveDestinationForArm -> refuse if
null (404) -> SSRF-at-connect -> refuse if unsafe (403) -> provisionOutput.
A destination that resolved to a public IP at create-time but rebinds to
a private/metadata/CGNAT IP by connect-time is now refused, not
provisioned.

INERT: armExternalRtmpRestream requires BOTH EGRESS_ROUTER_ENABLED and
EGRESS_DEST_MGMT_ENABLED armed (default OFF); either flag off refuses
before any lookup. No existing call site invokes it, so prod is
byte-identical.

Consumes resolveDestinationForArm (egress-destinations.ts, wre#289) for
the decrypted destination. Part of Zoom Live Media epic wave-zoom#46.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e616e710-1ec8-4192-b9fc-5677db5ce8c9)

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fa54b4fa-995f-4b72-ad25-15b375e39707

📥 Commits

Reviewing files that changed from the base of the PR and between 7386cd5 and 06c4207.

📒 Files selected for processing (5)
  • src/egress-arm.ts
  • src/egress-cf-stream-live-output-client.ts
  • test/egress-arm-o1-restream.test.ts
  • test/egress-cf-stream-live-output-client.test.ts
  • test/egress-cf-stream-passthrough.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/w1-o1-ext-rtmp

Comment @coderabbitai help to get the list of available commands.

…int + kind guard + resolve try/catch

MEDIUM: CfStreamEgressLiveOutputClient.provisionOutput now re-runs validateDestinationUrl (SSRF-at-connect, fail-closed on reject or throw) before any CF output create — the shared chokepoint both CfStreamPassthroughEgressBackend.provision and armExternalRtmpRestream funnel into, so the passthrough path is covered even though it never called assertDestinationSafeAtConnect itself.
LOW: armExternalRtmpRestream now asserts dest.kind === "rtmp" and refuses (400) a mismatched destination before treating it as RTMP.
LOW: armExternalRtmpRestream now wraps resolveDestinationForArm in try/catch and refuses (500, fail-closed) on throw, matching its documented "never throws" contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 06c4207

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@yakimoto
yakimoto merged commit 947917a into main Jul 23, 2026
15 checks passed
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.

1 participant