Skip to content

feat(cloud): Add managed relay tunnels and APN service#2837

Draft
juliusmarminge wants to merge 8 commits into
codex/environment-httpapi-client-runtimefrom
codex/relay-managed-tunnels-auth-infra
Draft

feat(cloud): Add managed relay tunnels and APN service#2837
juliusmarminge wants to merge 8 commits into
codex/environment-httpapi-client-runtimefrom
codex/relay-managed-tunnels-auth-infra

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented May 28, 2026

Stack

Summary

This stacked draft PR adds the relay-managed tunnel and cloud authentication work on top of the mobile remote-runtime PR. General collection/performance rewrites from #2854 and the TypeScript/Effect tooling base are now on main.

  • add the relay worker/infrastructure package, persistence, APNs delivery, managed endpoint provisioning, observability, migrations, and tests
  • add standards-oriented relay authentication: DPoP proof handling, JWT/JWS signing and verification, OAuth-style token exchange/scopes, replay protections, and environment proof flows
  • add shared client-runtime/contracts/shared modules for managed relay operation across web and Expo mobile clients
  • add web, desktop, and mobile cloud linking and managed-environment flows, including mobile agent-awareness/live-activity registration
  • route relay-specific hashing and randomness through effect/Crypto while retaining Expo-compatible implementations

Validation

  • bun fmt
  • bun lint (passes with 8 existing web warnings)
  • bun lint:mobile
  • bun typecheck
  • cd infra/relay && bun run test (103 passed, 5 skipped)
  • cd apps/mobile && bun run test (135 passed)
  • cd apps/web && bun run test (1005 passed)
  • cd apps/server && bun run test (1075 passed, 4 skipped)

Rebase Note

General collection/performance rewrites from #2854 are now merged into main; mobile command metadata, pairing-URL redaction, and shared-runtime Crypto cleanup remain in #2013. This PR retains the managed-relay changes to the mobile connection contract and runtime above those inherited lower-layer changes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4e659b36-5b70-44b0-9c1e-72381b45c0d1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/relay-managed-tunnels-auth-infra

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

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels May 28, 2026
Comment thread apps/server/src/cloud/http.ts
Comment thread apps/mobile/src/features/agent-awareness/liveActivityPreferences.ts
Comment thread apps/mobile/src/app/settings/index.tsx
Comment thread packages/client-runtime/src/remote.ts Outdated
Comment thread apps/server/src/cloud/http.ts Outdated
Comment thread infra/relay/src/api.ts Outdated
Comment thread infra/relay/src/services/EnvironmentConnector.ts
Comment thread infra/relay/src/environments/EnvironmentCredentials.ts
Comment thread apps/server/src/cloud/ManagedEndpointRuntime.ts
Comment thread apps/desktop/src/app/DesktopCloudAuth.ts
Comment thread apps/mobile/src/features/agent-awareness/notificationNavigation.ts
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from 8480c92 to e3ab348 Compare May 28, 2026 08:13
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from a7ed828 to b868fee Compare May 28, 2026 08:16
Comment thread apps/mobile/src/features/agent-awareness/remoteRegistration.ts
Comment thread apps/mobile/src/features/cloud/linkEnvironment.ts Outdated
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from e3ab348 to 436b1b9 Compare May 28, 2026 16:38
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from b868fee to 589e2ed Compare May 28, 2026 16:38
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from 436b1b9 to d20a8ce Compare May 28, 2026 16:46
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch 2 times, most recently from 63a525d to 8027af0 Compare May 28, 2026 17:41
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch 2 times, most recently from 6c0e54d to f15e2ba Compare May 28, 2026 18:00
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from 8027af0 to 1a912f6 Compare May 28, 2026 18:00
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from f15e2ba to 71e0186 Compare May 28, 2026 18:14
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from 1a912f6 to 90bf2b3 Compare May 28, 2026 18:14
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from 71e0186 to e721336 Compare May 28, 2026 19:50
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch 2 times, most recently from e63e3f4 to ba9802d Compare May 28, 2026 20:26
Comment thread infra/relay/src/environments/EnvironmentCredentials.ts
Comment thread apps/server/src/auth/dpop.ts Outdated
Comment thread apps/web/src/cloud/desktopClerk.tsx Outdated
Comment thread apps/web/src/cloud/desktopClerk.tsx Outdated
Comment thread apps/web/src/cloud/desktopAuth.ts
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from 22e103a to 60b7d8d Compare May 28, 2026 21:01
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from ba9802d to 8789910 Compare May 28, 2026 21:02
Comment thread apps/mobile/src/features/agent-awareness/liveActivityController.ts
Comment thread apps/desktop/src/app/DesktopCloudAuthTokenStore.ts
Comment thread infra/relay/src/observability/Metrics.ts Outdated
@juliusmarminge juliusmarminge force-pushed the t3code/mobile-remote-connect branch from 60b7d8d to ee4ec05 Compare May 28, 2026 21:42
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from 8789910 to f7ac694 Compare May 28, 2026 21:43
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch 4 times, most recently from c06b655 to 4c50731 Compare May 29, 2026 07:50
@juliusmarminge juliusmarminge changed the base branch from t3code/mobile-remote-connect to codex/environment-httpapi-client-runtime May 29, 2026 07:50
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from 4c50731 to 7deb0c4 Compare May 29, 2026 17:27
Comment thread apps/server/src/auth/http.ts Outdated
@juliusmarminge juliusmarminge changed the title [codex] Add managed relay tunnels and standards-based auth feat(cloud): Add managed relay tunnels and standards-based auth May 29, 2026
@juliusmarminge juliusmarminge changed the title feat(cloud): Add managed relay tunnels and standards-based auth feat(cloud): Add managed relay tunnels and APN service May 29, 2026
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch 3 times, most recently from bf992b4 to d374900 Compare May 29, 2026 23:14
Comment thread apps/web/src/cloud/desktopClerk.tsx Outdated
Comment thread apps/web/src/cloud/desktopClerk.tsx
Comment thread apps/web/src/cloud/desktopClerk.tsx
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from a668bac to a42a3f5 Compare May 29, 2026 23:57
@juliusmarminge juliusmarminge force-pushed the codex/environment-httpapi-client-runtime branch from 597e56d to f9c9f4d Compare May 30, 2026 00:05
@juliusmarminge juliusmarminge force-pushed the codex/relay-managed-tunnels-auth-infra branch from a42a3f5 to 2627b33 Compare May 30, 2026 00:06
Comment thread infra/relay/src/worker.ts
Comment thread apps/desktop/src/app/DesktopCloudAuth.ts
Comment thread apps/server/src/cloud/ManagedEndpointRuntime.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

const expectedMetadata = {

The cache invalidation logic at line 290 only checks expectedMetadata, which omits the environment variables embedded by writeDevelopmentLauncherScript. When the metadata matches, the function returns early at line 293 without regenerating the launcher script, even if VITE_DEV_SERVER_URL or T3CODE_PORT has changed. This causes the app to use stale environment variables from a previous run — for example, attempting to connect to a Vite dev server port that is no longer running.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/desktop/scripts/electron-launcher.mjs around line 277:

The cache invalidation logic at line 290 only checks `expectedMetadata`, which omits the environment variables embedded by `writeDevelopmentLauncherScript`. When the metadata matches, the function returns early at line 293 without regenerating the launcher script, even if `VITE_DEV_SERVER_URL` or `T3CODE_PORT` has changed. This causes the app to use stale environment variables from a previous run — for example, attempting to connect to a Vite dev server port that is no longer running.

Evidence trail:
apps/desktop/scripts/electron-launcher.mjs lines 277-294 (expectedMetadata definition and early return), lines 97-130 (writeDevelopmentLauncherScript embedding env vars into the launcher script), lines 300-302 (writeDevelopmentLauncherScript only called when cache is invalidated)

Comment on lines +254 to +256
const existingDnsRecordId = yield* HttpClientRequest.make("GET")(
"/zones/${cf.zoneId}/dns_records",
).pipe(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High environments/ManagedEndpointProvider.ts:254

The URL at line 255 uses double quotes with ${cf.zoneId}, so the literal string /zones/${cf.zoneId}/dns_records is sent to the API instead of the actual zone ID. Line 269-270 correctly use backticks for template literals. Consider changing to backticks to interpolate the zone ID.

-      const existingDnsRecordId = yield* HttpClientRequest.make("GET")(
-        "/zones/${cf.zoneId}/dns_records",
+      const existingDnsRecordId = yield* HttpClientRequest.make("GET")(
+        `/zones/${cf.zoneId}/dns_records`,
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file infra/relay/src/environments/ManagedEndpointProvider.ts around lines 254-256:

The URL at line 255 uses double quotes with `${cf.zoneId}`, so the literal string `/zones/${cf.zoneId}/dns_records` is sent to the API instead of the actual zone ID. Line 269-270 correctly use backticks for template literals. Consider changing to backticks to interpolate the zone ID.

Evidence trail:
infra/relay/src/environments/ManagedEndpointProvider.ts lines 254-270 at REVIEWED_COMMIT: line 255 uses double quotes ("/zones/${cf.zoneId}/dns_records") while lines 269-270 use backticks (`/zones/${cf.zoneId}/dns_records/${id}` and `/zones/${cf.zoneId}/dns_records`).

Comment thread infra/relay/src/worker.ts
Comment on lines +249 to +250
Effect.provide(runtimeLayer),
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium src/worker.ts:249

The queue message handler and cron handler create spans using Stream.withSpan and Effect.withSpan, but they only provide runtimeLayer which does not include the tracer. This means spans from background jobs are silently dropped instead of being exported to Axiom, despite the explicit instrumentation. Consider providing relayTraceLayer to these handlers, similar to the HTTP fetch handler at line 270.

        Effect.provide(runtimeLayer),
+        Effect.provide(relayTraceLayer),
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file infra/relay/src/worker.ts around lines 249-250:

The queue message handler and cron handler create spans using `Stream.withSpan` and `Effect.withSpan`, but they only provide `runtimeLayer` which does not include the tracer. This means spans from background jobs are silently dropped instead of being exported to Axiom, despite the explicit instrumentation. Consider providing `relayTraceLayer` to these handlers, similar to the HTTP fetch handler at line 270.

Evidence trail:
infra/relay/src/worker.ts lines 170-176 (relayTraceLayer definition with OtlpTracer), lines 178-213 (runtimeLayer definition without tracer), line 242 (Stream.withSpan in queue handler), line 246 (Effect.withSpan in queue handler), line 249 (Effect.provide(runtimeLayer) - no tracer), line 256 (Effect.withSpan in cron handler), line 257 (Effect.provide(runtimeLayer) - no tracer), line 270 (HTTP handler uses relayTraceLayer). infra/relay/src/observability.ts lines 53-72 (makeRelayTraceLayer creates OtlpTracer.layer for Axiom export).

Comment thread infra/relay/src/worker.ts
Comment on lines +162 to +163
managedEndpointBaseDomain: yield* managedEndpointZoneId,
cloudflareZoneId: yield* managedEndpointZoneId,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High src/worker.ts:162

Both managedEndpointBaseDomain and cloudflareZoneId are set to managedEndpointZoneId (the zone ID), but managedEndpointBaseDomain semantically requires the domain name (e.g., "ineededadomain.com"). The ManagedEndpointZone provides zoneName which contains the correct value, but it is never extracted or used. This will cause managed endpoint domain construction to use an invalid zone ID string instead of the actual domain name.

-        managedEndpointBaseDomain: yield* managedEndpointZoneId,
+        managedEndpointBaseDomain: yield* managedEndpointZone.zoneName,
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file infra/relay/src/worker.ts around lines 162-163:

Both `managedEndpointBaseDomain` and `cloudflareZoneId` are set to `managedEndpointZoneId` (the zone ID), but `managedEndpointBaseDomain` semantically requires the domain name (e.g., "ineededadomain.com"). The `ManagedEndpointZone` provides `zoneName` which contains the correct value, but it is never extracted or used. This will cause managed endpoint domain construction to use an invalid zone ID string instead of the actual domain name.

Evidence trail:
infra/relay/src/managedEndpointStack.ts:9-29 (ManagedEndpointZone returns zoneId, zoneName, dnsToken; zoneName = zone.name = 'ineededadomain.com')
infra/relay/src/worker.ts:140 (only zoneId extracted, zoneName ignored)
infra/relay/src/worker.ts:162-163 (both managedEndpointBaseDomain and cloudflareZoneId assigned from managedEndpointZoneId)
infra/relay/src/environments/ManagedEndpointProvider.ts:131 (baseDomain: settings.managedEndpointBaseDomain)
infra/relay/src/environments/ManagedEndpointProvider.ts:149 (baseDomain used in hostname construction: `...${baseDomain}`)

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant