Skip to content

fix(sdk): preserve tunnel half-close responses#996

Closed
G4614 wants to merge 1 commit into
boxlite-ai:mainfrom
G4614:codex/runner-guest-port-connect
Closed

fix(sdk): preserve tunnel half-close responses#996
G4614 wants to merge 1 commit into
boxlite-ai:mainfrom
G4614:codex/runner-guest-port-connect

Conversation

@G4614

@G4614 G4614 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Moved the half-close fix into #985 so this PR no longer carries a separate change.

Test plan:

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds box service-port tunneling across the API, proxy, runner, core runtime, C/Go/Node/Python SDKs, CLI, OpenAPI contracts, infrastructure, and end-to-end tests. It also updates preview URL encoding, forwarding headers, WebSocket path matching, and public-box defaults.

Changes

Network tunneling and service previews

Layer / File(s) Summary
API preview URLs and tunnel contracts
apps/api/..., openapi/..., apps/infra/sst.config.ts
Preview URLs now support encoded box IDs and service ports, public boxes default to true, and a REST tunnel descriptor endpoint returns { uri }.
Trusted forwarding and proxy routing
apps/common-go/..., apps/proxy/...
Forwarded headers are normalized and rewritten, direct-preview IDs are decoded, escaped paths are preserved, and HTTP CONNECT requests are proxied bidirectionally to runners.
Runner guest-port handling
apps/runner/...
Runner routes expose HTTP proxy and raw tunnel handlers, validate ports, preserve escaped paths, rewrite trusted headers, and connect to guest services.
Core REST and local tunnel backends
src/boxlite/...
Reusable tunnels now expose stable URI or Unix-socket endpoints and create a fresh connection per call; local and REST-backed network backends are implemented.
Cross-language SDK APIs
sdks/c/..., sdks/go/..., sdks/node/..., sdks/python/...
C, Go, Node, and Python bindings expose network handles, tunnel creation, endpoint lookup, connection APIs, lifecycle management, and exports.
CLI and validation
src/cli/..., scripts/test/e2e/..., apps/runner/...
A tunnel CLI command and SDK/runner integration coverage validate service-port connectivity and repeated connections.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: javascript

Suggested reviewers: dorianzheng

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PublicProxy
  participant RunnerAPI
  participant BoxNetwork
  participant GuestService

  Client->>PublicProxy: CONNECT preview host
  PublicProxy->>RunnerAPI: CONNECT /network/tunnel?port=port
  RunnerAPI->>BoxNetwork: Dial guest port
  BoxNetwork->>GuestService: Open service connection
  GuestService-->>BoxNetwork: Bidirectional stream
  BoxNetwork-->>RunnerAPI: Tunnel stream
  RunnerAPI-->>PublicProxy: 200 Connection Established
  PublicProxy-->>Client: Relay tunnel bytes
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.40% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning It has a summary and test plan, but it omits the required ## Changes section and template headings. Add the required ## Summary, ## Changes, and ## How to verify sections, and list the notable code changes as bullets.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the tunnel half-close semantics change, though it is narrower than the full PR scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@G4614
G4614 force-pushed the codex/runner-guest-port-connect branch from 8246d7d to e83feda Compare July 17, 2026 05:57
@G4614
G4614 changed the base branch from stack/shared-forwarded-proxy to main July 17, 2026 05:58
@G4614 G4614 mentioned this pull request Jul 17, 2026
3 tasks
@zombee0

zombee0 commented Jul 19, 2026

Copy link
Copy Markdown

Does the current implementation establish a new runner-to-box connection for every HTTP request? Does each request require re-authentication? Is the user base characterized by low concurrency? Is the performance acceptable?

@G4614 G4614 changed the title feat(runner): proxy guest service ports refactor(tunnel): stream guest ports over HTTP Jul 21, 2026
@G4614
G4614 marked this pull request as ready for review July 21, 2026 07:09
@G4614
G4614 requested a review from a team as a code owner July 21, 2026 07:09
@boxlite-agent

boxlite-agent Bot commented Jul 21, 2026

Copy link
Copy Markdown

📦 BoxLite review — couldn't complete

claude exited 1

stdout:
{"type":"result","subtype":"success","is_error":true,"api_error_status":403,"duration_ms":335,"duration_api_ms":0,"num_turns":1,"result":"Your organization has disabled Claude subscription access for Claude Code · Use an Anthropic API key instead, or ask your admin to enable access","stop_reason":"stop_sequence","session_id":"4f4a073b-2f15-493a-a59d-860d1eeb4274","total_cost_usd":0,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{},"permission_denials":[],"terminal_reason":"api_error","fast_mode_state":"off","uuid":"2cb0211f-75ad-4d23-a82a-d126e2cef30c"}

stderr:
<empty>

powered by BoxLite

@G4614
G4614 enabled auto-merge July 21, 2026 07:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/boxlite/src/net/mod.rs (1)

651-673: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale comments after removing into_fd(). The test no longer recovers an fd, but lines 651–653 and the trailing line 672 still describe fd recoverability / "SDK fd-bridge relies on it," which no longer holds. Trim these so the test intent stays accurate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/boxlite/src/net/mod.rs` around lines 651 - 673, Remove the stale
fd-recovery and SDK fd-bridge claims from the test comments surrounding
BoxInternalTunnel::from_local. Keep comments describing the Unix socketpair,
bidirectional AsyncRead/AsyncWrite behavior, and peer handling, but delete the
trailing comment about recovering an owned OS fd.
🧹 Nitpick comments (6)
src/cli/src/commands/tunnel.rs (1)

22-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

No test coverage for the new tunnel command.

execute has no accompanying unit test in this batch (unlike the port-validation checks mirrored in the SDK tunnel() bindings, which do have tests). Consider adding at least a test for the port == 0 rejection and the BoxEndpoint::UnixSocket error path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/src/commands/tunnel.rs` around lines 22 - 50, Add unit tests for the
tunnel command’s execute flow, covering port == 0 rejection and the
BoxEndpoint::UnixSocket error path. Reuse existing CLI test patterns and
fixtures/mocks around execute, asserting the validation error and remote REST
profile error respectively without changing production behavior.
sdks/python/tests/test_tunnel.py (1)

38-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add comprehensive docstrings to public test functions.

As per coding guidelines, comprehensive docstrings must be written for all public functions and classes. While these are test functions, they are public and should include a brief docstring explaining the test's purpose.

  • sdks/python/tests/test_tunnel.py#L38-L38: Add a docstring to test_endpoint_returns_stable_unix_socket_path.
  • sdks/python/tests/test_tunnel.py#L49-L49: Add a docstring to test_connect_opens_fresh_sockets.
  • sdks/python/tests/test_tunnel.py#L73-L73: Add a docstring to test_tunnel_requires_a_started_box.
  • sdks/python/tests/test_dev_tunnel_e2e.py#L136-L136: Add a docstring to test_local_box_tunnel_endpoint_and_repeated_connects.
  • sdks/python/tests/test_dev_tunnel_e2e.py#L152-L152: Add a docstring to test_dev_cloud_tunnel_endpoint_and_repeated_connects.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/python/tests/test_tunnel.py` at line 38, Add brief purpose-focused
docstrings to test_endpoint_returns_stable_unix_socket_path,
test_connect_opens_fresh_sockets, and test_tunnel_requires_a_started_box in
sdks/python/tests/test_tunnel.py at lines 38-38, 49-49, and 73-73, respectively.
Also document test_local_box_tunnel_endpoint_and_repeated_connects and
test_dev_cloud_tunnel_endpoint_and_repeated_connects in
sdks/python/tests/test_dev_tunnel_e2e.py at lines 136-136 and 152-152,
describing the behavior each test verifies.

Source: Coding guidelines

sdks/python/boxlite/simplebox.py (1)

216-222: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant attribute check.

Since self._network is unconditionally initialized in __init__ (line 138), the hasattr check here is redundant and can be simplified.

♻️ Proposed refactor
     `@property`
     def network(self) -> _SimpleBoxNetwork:
         """Get the box-scoped network handle."""
-        if not hasattr(self, "_network"):
-            self._network = _SimpleBoxNetwork(self)
         return self._network
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/python/boxlite/simplebox.py` around lines 216 - 222, Update the network
property to return the already-initialized self._network directly, removing the
redundant hasattr check and lazy _SimpleBoxNetwork construction while preserving
the existing _SimpleBoxNetwork handle.
sdks/python/boxlite/sync_api/_network.py (1)

18-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add type hints for connect and endpoint return values.

To match the BoxTunnel interface in simplebox.py, consider adding explicit return type hints (socket.socket and str) to these methods.

Add the socket import at the top of the file:

import socket
♻️ Proposed refactor
-    def connect(self):
+    def connect(self) -> socket.socket:
         """Open a blocking socket to the target service."""
         tunnel = self._box._sync(self._tunnel.connect())
         tunnel.setblocking(True)
         return tunnel
 
-    def endpoint(self):
+    def endpoint(self) -> str:
         """Return the cloud URL or local Unix socket path."""
         return self._box._sync(self._tunnel.endpoint())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/python/boxlite/sync_api/_network.py` around lines 18 - 26, Update the
synchronous tunnel methods connect and endpoint with explicit return annotations
of socket.socket and str, respectively, and import socket in the module so the
annotations resolve.
apps/api/src/boxlite-rest/boxlite-proxy.controller.ts (1)

195-208: 🚀 Performance & Scalability | 🔵 Trivial

Re: reviewer question on per-request runner connections/re-auth.

Confirming from this code: yes — every octet-stream tunnel request flowing through proxyNetworkTunnelproxyToRunner performs a fresh boxService.findOneByIdOrName DB lookup, a fresh runnerService.findOne, and instantiates a brand-new createProxyMiddleware(...) (with its own outgoing connection to the runner) per HTTP request. This mirrors the pre-existing pattern used by proxyExec/proxyFiles/proxyMetrics, so it isn't a regression from this PR, but it does mean concurrency/performance for guest-port tunneling is bounded by this per-request overhead (DB round-trip + new outbound connection) rather than a persistently reused runner connection. Worth keeping in mind if/when the expected request rate per tunnel grows, since (unlike the WS proxy in boxlite-ws-proxy.service.ts, which builds one createProxyMiddleware instance in the constructor) this path builds a new middleware instance on every call.

Also applies to: 242-290

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts` around lines 195 -
208, Review the per-request connection behavior in proxyNetworkTunnel and
proxyToRunner, including the related logic around the alternate tunnel path, and
avoid creating a fresh createProxyMiddleware instance and runner lookup for
every streaming request. Reuse a persistent proxy middleware/runner connection
pattern comparable to boxlite-ws-proxy.service.ts while preserving
authentication, request routing, and octet-stream validation.
apps/runner/pkg/api/controllers/proxy.go (1)

263-264: 🚀 Performance & Scalability | 🔵 Trivial

Per-request transport prevents connection reuse.

NewGuestPortTransport builds a fresh transport that dials a new guest tunnel per request, and defer transport.CloseIdleConnections() discards any keep-alive connection once the handler returns, so nothing is reused across requests. This is fine for the expected low-concurrency preview traffic called out in the PR discussion, but if request volume grows, consider caching a transport per (boxId, port) to amortize tunnel setup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/runner/pkg/api/controllers/proxy.go` around lines 263 - 264, Update the
proxy handler around NewGuestPortTransport to reuse transports across requests
by caching them per (boxId, port) pair instead of creating and closing one for
every request. Ensure cached transports remain available for connection reuse
and are safely managed when boxes or ports are no longer needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts`:
- Around line 182-212: Update proxyNetworkTunnel to await this.startHint(boxId,
authContext) before either the streaming proxyToRunner path or the
getPortPreviewUrl path, matching the startup handling in proxyExec, proxyFiles,
and proxyMetrics. Ensure the notification occurs after validating the port and
before any guest-facing request can autostart the box.

In `@sdks/python/boxlite/sync_api/_network.py`:
- Around line 35-38: Update SyncBoxTunnel's tunnel method to validate port
before calling _owner._create_tunnel, ensuring it is a valid integer port within
the supported range and raising the established input-validation error for
invalid values. Preserve the existing tunnel creation and SyncBoxTunnel return
flow for valid ports, matching SimpleBox._create_tunnel behavior.

In `@sdks/python/boxlite/sync_api/_simplebox.py`:
- Around line 258-264: Update the docstring of SyncSimpleBox.tunnel to describe
returning a lazy SyncBoxTunnel handle, not immediately opening a socket; mention
that callers must explicitly invoke .connect() to obtain the socket, while
leaving the method behavior unchanged.

In `@src/boxlite/src/litebox/box_impl.rs`:
- Around line 75-90: Update the listener accept loop around
listener.accept().await so transient accept errors are logged and the loop
continues instead of breaking and terminating the accept task. Preserve the
existing client-handling spawn and tunnel error logging, while reserving loop
termination only for explicitly unrecoverable listener states if such handling
already exists.

---

Outside diff comments:
In `@src/boxlite/src/net/mod.rs`:
- Around line 651-673: Remove the stale fd-recovery and SDK fd-bridge claims
from the test comments surrounding BoxInternalTunnel::from_local. Keep comments
describing the Unix socketpair, bidirectional AsyncRead/AsyncWrite behavior, and
peer handling, but delete the trailing comment about recovering an owned OS fd.

---

Nitpick comments:
In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts`:
- Around line 195-208: Review the per-request connection behavior in
proxyNetworkTunnel and proxyToRunner, including the related logic around the
alternate tunnel path, and avoid creating a fresh createProxyMiddleware instance
and runner lookup for every streaming request. Reuse a persistent proxy
middleware/runner connection pattern comparable to boxlite-ws-proxy.service.ts
while preserving authentication, request routing, and octet-stream validation.

In `@apps/runner/pkg/api/controllers/proxy.go`:
- Around line 263-264: Update the proxy handler around NewGuestPortTransport to
reuse transports across requests by caching them per (boxId, port) pair instead
of creating and closing one for every request. Ensure cached transports remain
available for connection reuse and are safely managed when boxes or ports are no
longer needed.

In `@sdks/python/boxlite/simplebox.py`:
- Around line 216-222: Update the network property to return the
already-initialized self._network directly, removing the redundant hasattr check
and lazy _SimpleBoxNetwork construction while preserving the existing
_SimpleBoxNetwork handle.

In `@sdks/python/boxlite/sync_api/_network.py`:
- Around line 18-26: Update the synchronous tunnel methods connect and endpoint
with explicit return annotations of socket.socket and str, respectively, and
import socket in the module so the annotations resolve.

In `@sdks/python/tests/test_tunnel.py`:
- Line 38: Add brief purpose-focused docstrings to
test_endpoint_returns_stable_unix_socket_path, test_connect_opens_fresh_sockets,
and test_tunnel_requires_a_started_box in sdks/python/tests/test_tunnel.py at
lines 38-38, 49-49, and 73-73, respectively. Also document
test_local_box_tunnel_endpoint_and_repeated_connects and
test_dev_cloud_tunnel_endpoint_and_repeated_connects in
sdks/python/tests/test_dev_tunnel_e2e.py at lines 136-136 and 152-152,
describing the behavior each test verifies.

In `@src/cli/src/commands/tunnel.rs`:
- Around line 22-50: Add unit tests for the tunnel command’s execute flow,
covering port == 0 rejection and the BoxEndpoint::UnixSocket error path. Reuse
existing CLI test patterns and fixtures/mocks around execute, asserting the
validation error and remote REST profile error respectively without changing
production behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 56686a1b-9c8c-4da7-9b22-b8e5d3ba672d

📥 Commits

Reviewing files that changed from the base of the PR and between 2411669 and 5c79e3e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (68)
  • apps/api-client-go/api/openapi.yaml
  • apps/api/src/box/dto/create-box.dto.ts
  • apps/api/src/box/dto/port-preview-url.dto.ts
  • apps/api/src/box/services/box.service.spec.ts
  • apps/api/src/box/services/box.service.ts
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.ts
  • apps/api/src/boxlite-rest/boxlite-rest-routing.spec.ts
  • apps/api/src/boxlite-rest/boxlite-ws-proxy.service.ts
  • apps/api/src/main.ts
  • apps/common-go/pkg/proxy/proxy.go
  • apps/common-go/pkg/proxy/proxy_test.go
  • apps/infra/sst.config.ts
  • apps/proxy/pkg/proxy/get_box_target.go
  • apps/proxy/pkg/proxy/get_box_target_test.go
  • apps/runner/pkg/api/controllers/proxy.go
  • apps/runner/pkg/api/controllers/proxy_integration_test.go
  • apps/runner/pkg/api/controllers/proxy_test.go
  • apps/runner/pkg/api/server.go
  • apps/runner/pkg/boxlite/guest_port_tunnel.go
  • openapi/box.openapi.yaml
  • scripts/build/build-runtime.sh
  • scripts/test/e2e/cases/test_node_tunnel.py
  • scripts/test/e2e/cases/test_sdk_tunnel.py
  • scripts/test/e2e/sdks/node/e2e_tunnel.ts
  • sdks/c/Cargo.toml
  • sdks/c/include/boxlite.h
  • sdks/c/src/lib.rs
  • sdks/c/src/network.rs
  • sdks/c/src/tests.rs
  • sdks/go/constants.go
  • sdks/go/tunnel.go
  • sdks/node/Cargo.toml
  • sdks/node/lib/index.ts
  • sdks/node/lib/native-contracts.ts
  • sdks/node/lib/simplebox.ts
  • sdks/node/src/box_handle.rs
  • sdks/node/src/lib.rs
  • sdks/node/src/network.rs
  • sdks/node/tests/tunnel.test.ts
  • sdks/python/Cargo.toml
  • sdks/python/boxlite/__init__.py
  • sdks/python/boxlite/simplebox.py
  • sdks/python/boxlite/sync_api/__init__.py
  • sdks/python/boxlite/sync_api/_box.py
  • sdks/python/boxlite/sync_api/_network.py
  • sdks/python/boxlite/sync_api/_simplebox.py
  • sdks/python/pytest.ini
  • sdks/python/src/box_handle.rs
  • sdks/python/src/lib.rs
  • sdks/python/src/network.rs
  • sdks/python/tests/test_dev_tunnel_e2e.py
  • sdks/python/tests/test_tunnel.py
  • src/boxlite/Cargo.toml
  • src/boxlite/src/litebox/box_impl.rs
  • src/boxlite/src/litebox/mod.rs
  • src/boxlite/src/litebox/network.rs
  • src/boxlite/src/net/gvproxy/services.rs
  • src/boxlite/src/net/mod.rs
  • src/boxlite/src/rest/client.rs
  • src/boxlite/src/rest/litebox.rs
  • src/boxlite/src/rest/runtime.rs
  • src/boxlite/src/runtime/backend.rs
  • src/boxlite/tests/gvproxy_backend.rs
  • src/cli/src/cli.rs
  • src/cli/src/commands/mod.rs
  • src/cli/src/commands/tunnel.rs
  • src/cli/src/main.rs
💤 Files with no reviewable changes (2)
  • src/boxlite/src/net/gvproxy/services.rs
  • src/boxlite/tests/gvproxy_backend.rs

Comment thread apps/api/src/boxlite-rest/boxlite-proxy.controller.ts
Comment thread sdks/python/boxlite/sync_api/_network.py
Comment thread sdks/python/boxlite/sync_api/_simplebox.py
Comment thread src/boxlite/src/litebox/box_impl.rs Outdated
@G4614 G4614 changed the title refactor(tunnel): stream guest ports over HTTP refactor(tunnel): route SDK streams through HTTP CONNECT Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
apps/api/src/boxlite-rest/boxlite-proxy.controller.ts (1)

186-205: ⚠️ Potential issue | 🟠 Major

Missing startHint autostart notification.

proxyNetworkTunnel is missing the startHint autostart notification. Every other guest-facing proxy method (proxyExec, proxyFiles, proxyMetrics) calls await this.startHint(boxId, authContext) before proxying. Without startHint, tunneling into a guest port on a stopped box will trigger an auto-start/re-stop race because the control plane's sync-states will promptly stop the box when it sees desiredState=STOPPED.

🐛 Proposed fix
     if (port < 1 || port > 65535) {
       return res.status(400).json({ error: 'port must be between 1 and 65535' })
     }
 
+    await this.startHint(boxId, authContext)
+
     const { url: uri } = await this.boxService.getPortPreviewUrl(boxId, authContext.organizationId, port)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts` around lines 186 -
205, Update proxyNetworkTunnel to await this.startHint(boxId, authContext)
before requesting the preview URL or issuing the tunnel ticket, matching the
existing proxyExec, proxyFiles, and proxyMetrics flows so stopped boxes receive
the autostart notification first.
🧹 Nitpick comments (2)
openapi/box.openapi.yaml (1)

1298-1313: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use snake_case for API response properties.

The BoxServiceEndpoint schema introduces connectUri in camelCase, which is inconsistent with the snake_case convention used across the rest of the API (e.g., box_id, created_at, disk_size_gb).

  • openapi/box.openapi.yaml#L1298-L1313: Rename connectUri to connect_uri.
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.ts#L186-L205: Return connect_uri instead of connectUri in the JSON response payload.
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts#L78-L99: Update the test assertion to expect connect_uri.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openapi/box.openapi.yaml` around lines 1298 - 1313, Rename the
BoxServiceEndpoint schema property from connectUri to connect_uri in
openapi/box.openapi.yaml (1298-1313), update the boxlite-proxy controller
response to return connect_uri in
apps/api/src/boxlite-rest/boxlite-proxy.controller.ts (186-205), and change the
corresponding assertion in
apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts (78-99) to expect
connect_uri.
apps/runner/pkg/api/controllers/proxy_test.go (1)

19-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't verify proxyBidirectionalStream waits for both directions to finish.

The test runs proxyBidirectionalStream via go and never synchronizes on its return, so it can't detect the single-<-done-receive bug (see proxy.go lines 159-171): the function could return well before guest's pong is actually delivered and the test would still pass. Consider running it synchronously (or with a completion channel) and asserting it returns only after both writes/reads complete.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/runner/pkg/api/controllers/proxy_test.go` around lines 19 - 46, The test
currently does not synchronize with proxyBidirectionalStream, so it cannot
verify completion of both relay directions. Update
TestProxyBidirectionalStreamRelaysBothDirections to use a completion channel or
equivalent synchronization, wait for proxyBidirectionalStream to return after
both ping and pong exchanges, and assert completion occurs only after both
writes and reads finish.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/proxy/pkg/proxy/proxy.go`:
- Around line 200-204: Update the http.Server initialization in the proxy setup
to add a suitable ReadTimeout alongside ReadHeaderTimeout, so routed non-CONNECT
requests have an overall read deadline. Keep the existing Addr, Handler, and
header-timeout configuration unchanged.

In `@apps/proxy/pkg/proxy/tunnel.go`:
- Around line 94-98: Update the TLS configuration in the HTTPS branch of the
tunnel connection logic to explicitly set MinVersion to tls.VersionTLS12 (or the
project’s approved TLS 1.3 minimum) when constructing tls.Config. Keep the
existing ServerName behavior and non-HTTPS dialing path unchanged.
- Around line 130-137: Add a CloseWrite method to bufferedConn that detects
whether the embedded net.Conn supports CloseWrite() error and forwards the call,
returning the underlying result; otherwise return an appropriate
unsupported-operation error. This ensures proxyTunnelStreams can detect and
half-close buffered connections.
- Around line 78-101: Update dialRunnerTunnel to enforce an explicit bounded
timeout for the runner-tunnel connection and TLS handshake, rather than relying
solely on the incoming request context. Configure the net.Dialer used by both
plain and TLS dialing with the established tunnel setup timeout, preserving
context cancellation while ensuring unreachable or slow runners cannot block
indefinitely.

In `@apps/runner/pkg/api/controllers/proxy.go`:
- Around line 159-171: Both bidirectional tunnel helpers return after only one
copy direction completes. In apps/runner/pkg/api/controllers/proxy.go lines
159-171, update proxyBidirectionalStream to wait for both done signals before
returning; apply the identical change in apps/proxy/pkg/proxy/tunnel.go lines
139-151 for proxyTunnelStreams. Preserve the existing two-goroutine streaming
behavior and deferred connection cleanup.

---

Duplicate comments:
In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts`:
- Around line 186-205: Update proxyNetworkTunnel to await this.startHint(boxId,
authContext) before requesting the preview URL or issuing the tunnel ticket,
matching the existing proxyExec, proxyFiles, and proxyMetrics flows so stopped
boxes receive the autostart notification first.

---

Nitpick comments:
In `@apps/runner/pkg/api/controllers/proxy_test.go`:
- Around line 19-46: The test currently does not synchronize with
proxyBidirectionalStream, so it cannot verify completion of both relay
directions. Update TestProxyBidirectionalStreamRelaysBothDirections to use a
completion channel or equivalent synchronization, wait for
proxyBidirectionalStream to return after both ping and pong exchanges, and
assert completion occurs only after both writes and reads finish.

In `@openapi/box.openapi.yaml`:
- Around line 1298-1313: Rename the BoxServiceEndpoint schema property from
connectUri to connect_uri in openapi/box.openapi.yaml (1298-1313), update the
boxlite-proxy controller response to return connect_uri in
apps/api/src/boxlite-rest/boxlite-proxy.controller.ts (186-205), and change the
corresponding assertion in
apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts (78-99) to expect
connect_uri.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d7ebc8b-d917-4dde-a7e8-9664c51c7fa8

📥 Commits

Reviewing files that changed from the base of the PR and between 5c79e3e and 4ad710c.

📒 Files selected for processing (25)
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.ts
  • apps/api/src/boxlite-rest/boxlite-rest.module.ts
  • apps/api/src/boxlite-rest/boxlite-tunnel-ticket.service.spec.ts
  • apps/api/src/boxlite-rest/boxlite-tunnel-ticket.service.ts
  • apps/api/src/config/configuration.ts
  • apps/common-go/pkg/cache/redis_cache.go
  • apps/infra/sst.config.ts
  • apps/proxy/pkg/proxy/proxy.go
  • apps/proxy/pkg/proxy/tunnel.go
  • apps/proxy/pkg/proxy/tunnel_test.go
  • apps/runner/pkg/api/controllers/proxy.go
  • apps/runner/pkg/api/controllers/proxy_test.go
  • apps/runner/pkg/api/server.go
  • openapi/box.openapi.yaml
  • sdks/c/include/boxlite.h
  • sdks/c/src/network.rs
  • sdks/go/tunnel.go
  • sdks/node/src/network.rs
  • sdks/python/src/network.rs
  • src/boxlite/Cargo.toml
  • src/boxlite/src/litebox/network.rs
  • src/boxlite/src/rest/client.rs
  • src/boxlite/src/rest/litebox.rs
  • src/cli/src/commands/tunnel.rs
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/runner/pkg/api/server.go
  • src/cli/src/commands/tunnel.rs
  • src/boxlite/Cargo.toml
  • src/boxlite/src/rest/litebox.rs
  • sdks/node/src/network.rs
  • sdks/c/include/boxlite.h
  • sdks/c/src/network.rs
  • sdks/go/tunnel.go
  • sdks/python/src/network.rs
  • src/boxlite/src/litebox/network.rs

Comment thread apps/proxy/pkg/proxy/proxy.go
Comment thread apps/proxy/pkg/proxy/tunnel.go Outdated
Comment thread apps/proxy/pkg/proxy/tunnel.go
Comment thread apps/proxy/pkg/proxy/tunnel.go Outdated
Comment thread apps/runner/pkg/api/controllers/proxy.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/proxy/pkg/proxy/proxy.go (1)

103-113: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Initialize tunnelTickets when Redis is disabled.

The new cache is assigned only in the config.Redis != nil branch, while connectAwareHandler routes CONNECT requests in both modes. In a no-Redis configuration, tunnel handling can therefore dereference a nil cache or reject every ticket.

 	} else {
 		proxy.boxRunnerCache = common_cache.NewMapCache[RunnerInfo](ctx)
 		proxy.runnerCache = common_cache.NewMapCache[RunnerInfo](ctx)
 		proxy.boxPublicCache = common_cache.NewMapCache[bool](ctx)
 		proxy.boxAuthKeyValidCache = common_cache.NewMapCache[bool](ctx)
 		proxy.boxLastActivityUpdateCache = common_cache.NewMapCache[bool](ctx)
+		proxy.tunnelTickets = common_cache.NewMapCache[TunnelTicket](ctx)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/proxy/pkg/proxy/proxy.go` around lines 103 - 113, Initialize
proxy.tunnelTickets in the config.Redis == nil branch using the in-memory cache
implementation, alongside the other MapCache fields. Ensure connectAwareHandler
can access a non-nil tunnelTickets cache in both Redis-enabled and no-Redis
configurations.
♻️ Duplicate comments (2)
apps/proxy/pkg/proxy/proxy.go (1)

200-203: 🩺 Stability & Availability | 🟠 Major

Add read deadlines to the HTTP server.

This remains unresolved from the previous review: the server has neither ReadHeaderTimeout nor ReadTimeout. Non-CONNECT requests delegated to router can hold connections open with slow request bodies, exhausting proxy resources. Choose values compatible with supported request sizes and CONNECT handshakes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/proxy/pkg/proxy/proxy.go` around lines 200 - 203, Update the http.Server
initialization in the proxy handler setup to configure both ReadHeaderTimeout
and ReadTimeout with finite values. Choose timeouts that allow supported request
sizes and CONNECT handshakes while preventing slow non-CONNECT requests routed
through router from holding connections indefinitely.

Source: Linters/SAST tools

apps/api/src/boxlite-rest/boxlite-proxy.controller.ts (1)

186-204: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

proxyNetworkTunnel is missing the startHint autostart notification.

Every other guest-facing proxy method (proxyExec, proxyFiles, proxyMetrics) calls await this.startHint(boxId, authContext) before proxying, because a proxied call into a stopped box's runtime auto-starts the VM (Box::live_state()) without the control-plane DB knowing — without startHint, sync-states will see desiredState=STOPPED and re-stop the box shortly after tunnel traffic arrives. proxyNetworkTunnel skips this call, so tunneling into a guest port on a stopped box is likely to trigger the exact auto-start/re-stop race the ensureStartedForProxy docstring describes.

🐛 Proposed fix
     if (port < 1 || port > 65535) {
       return res.status(400).json({ error: 'port must be between 1 and 65535' })
     }
 
+    await this.startHint(boxId, authContext)
+
     const { url: uri } = await this.boxService.getPortPreviewUrl(boxId, authContext.organizationId, port)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts` around lines 186 -
204, Update proxyNetworkTunnel to await startHint(boxId, authContext) before
requesting the port preview URL or issuing the tunnel ticket, matching the
startup notification flow used by proxyExec, proxyFiles, and proxyMetrics.
🧹 Nitpick comments (2)
sdks/python/boxlite/sync_api/_simplebox.py (1)

258-273: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the public networking API contract completely.

The lazy-tunnel wording is now correct, but both public APIs should document their arguments/return values and the RuntimeError raised before startup, as required by the SDK guidelines.

📝 Suggested documentation
     def tunnel(self, port: int):
-        """Return a lazy tunnel handle; call ``connect()`` to open its socket."""
+        """Return a lazy tunnel handle for a guest port.
+
+        Args:
+            port: Guest port to expose.
+
+        Returns:
+            A tunnel handle; call ``connect()`` to open its socket.
+
+        Raises:
+            RuntimeError: If the box has not been started.
+        """

     `@property`
     def network(self):
-        """Get the box-scoped network handle."""
+        """Return the box-scoped network handle.
+
+        Raises:
+            RuntimeError: If the box has not been started.
+        """
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/python/boxlite/sync_api/_simplebox.py` around lines 258 - 273, Complete
the docstrings for the public SyncSimpleBox.tunnel and SyncSimpleBox.network
APIs, documenting the tunnel port argument, returned handle/value, and the
RuntimeError raised when the box has not started. Preserve the existing lazy
tunnel behavior and startup validation.

Source: Coding guidelines

src/boxlite/src/rest/client.rs (1)

346-346: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Tower Service::call requires poll_ready.

Calling .call() directly on a tower::Service without first ensuring .poll_ready() returns Ready violates the Tower service contract. Although hyper_rustls::HttpsConnector happens to always be ready without blocking, it's safer and more idiomatic to use tower::ServiceExt::oneshot.

🛠️ Proposed fix

Import ServiceExt at the use-site and apply .oneshot():

-        let io = tokio::time::timeout(TUNNEL_SETUP_TIMEOUT, connector.call(uri.clone()))
+        use tower::ServiceExt;
+        let io = tokio::time::timeout(TUNNEL_SETUP_TIMEOUT, connector.oneshot(uri.clone()))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/boxlite/src/rest/client.rs` at line 346, Update the tunnel setup flow
around the connector service to import and use Tower’s ServiceExt::oneshot
instead of calling connector.call directly, ensuring readiness is polled before
dispatch while preserving the existing timeout and URI handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/proxy/pkg/proxy/proxy.go`:
- Line 202: Update the CONNECT handling around proxy.handleTunnelConnect and
connectAwareHandler so established hijacked tunnels are registered with
shutdownWg before being served and released when they close, ensuring graceful
shutdown waits for active CONNECT streams. Preserve the existing handler routing
while covering all CONNECT tunnel lifetimes.

---

Outside diff comments:
In `@apps/proxy/pkg/proxy/proxy.go`:
- Around line 103-113: Initialize proxy.tunnelTickets in the config.Redis == nil
branch using the in-memory cache implementation, alongside the other MapCache
fields. Ensure connectAwareHandler can access a non-nil tunnelTickets cache in
both Redis-enabled and no-Redis configurations.

---

Duplicate comments:
In `@apps/api/src/boxlite-rest/boxlite-proxy.controller.ts`:
- Around line 186-204: Update proxyNetworkTunnel to await startHint(boxId,
authContext) before requesting the port preview URL or issuing the tunnel
ticket, matching the startup notification flow used by proxyExec, proxyFiles,
and proxyMetrics.

In `@apps/proxy/pkg/proxy/proxy.go`:
- Around line 200-203: Update the http.Server initialization in the proxy
handler setup to configure both ReadHeaderTimeout and ReadTimeout with finite
values. Choose timeouts that allow supported request sizes and CONNECT
handshakes while preventing slow non-CONNECT requests routed through router from
holding connections indefinitely.

---

Nitpick comments:
In `@sdks/python/boxlite/sync_api/_simplebox.py`:
- Around line 258-273: Complete the docstrings for the public
SyncSimpleBox.tunnel and SyncSimpleBox.network APIs, documenting the tunnel port
argument, returned handle/value, and the RuntimeError raised when the box has
not started. Preserve the existing lazy tunnel behavior and startup validation.

In `@src/boxlite/src/rest/client.rs`:
- Line 346: Update the tunnel setup flow around the connector service to import
and use Tower’s ServiceExt::oneshot instead of calling connector.call directly,
ensuring readiness is polled before dispatch while preserving the existing
timeout and URI handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e5dd83d-bc5d-41b0-a7e8-ece7c7072532

📥 Commits

Reviewing files that changed from the base of the PR and between 4ad710c and c0be538.

📒 Files selected for processing (14)
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.ts
  • apps/proxy/pkg/proxy/proxy.go
  • apps/proxy/pkg/proxy/tunnel.go
  • apps/proxy/pkg/proxy/tunnel_test.go
  • apps/runner/pkg/api/controllers/proxy.go
  • apps/runner/pkg/api/controllers/proxy_test.go
  • openapi/box.openapi.yaml
  • sdks/python/boxlite/sync_api/_network.py
  • sdks/python/boxlite/sync_api/_simplebox.py
  • sdks/python/tests/test_tunnel.py
  • src/boxlite/Cargo.toml
  • src/boxlite/src/litebox/box_impl.rs
  • src/boxlite/src/rest/client.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • apps/proxy/pkg/proxy/tunnel_test.go
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts
  • sdks/python/boxlite/sync_api/_network.py
  • openapi/box.openapi.yaml
  • src/boxlite/src/litebox/box_impl.rs
  • apps/proxy/pkg/proxy/tunnel.go
  • src/boxlite/Cargo.toml
  • apps/runner/pkg/api/controllers/proxy_test.go
  • apps/runner/pkg/api/controllers/proxy.go

Comment thread apps/proxy/pkg/proxy/proxy.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/proxy/pkg/proxy/tunnel.go (1)

117-123: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Path is stripped from CONNECT requests, causing tunnel failure.

Go's http.Request.Write method specifically handles the CONNECT method by using req.URL.Host as the Request-URI and completely ignoring the path. Because req is created with "http://"+host+path, req.URL.Host is populated, and req.Write(conn) will output CONNECT {host} HTTP/1.1. The runner will never receive the /v1/boxes/... path and will likely return a 404 Not Found.

To preserve the path in the Request-URI while maintaining the Host header, initialize the request with just the path.

🐛 Proposed fix
-	path := fmt.Sprintf("/v1/boxes/%s/network/tunnel?port=%d", url.PathEscape(boxID), port)
-	req, err := http.NewRequestWithContext(ctx, http.MethodConnect, "http://"+host+path, nil)
+	path := fmt.Sprintf("/v1/boxes/%s/network/tunnel?port=%d", url.PathEscape(boxID), port)
+	req, err := http.NewRequestWithContext(ctx, http.MethodConnect, path, nil)
 	if err != nil {
 		conn.Close()
 		return nil, err
 	}
 	req.Host = host
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/proxy/pkg/proxy/tunnel.go` around lines 117 - 123, Update the CONNECT
request construction near req.Host so http.NewRequestWithContext receives only
path rather than "http://"+host+path, then retain host in req.Host. Preserve the
existing context, method, error cleanup, and escaped tunnel path so req.Write
sends the full path as the Request-URI.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/proxy/pkg/proxy/tunnel.go`:
- Around line 28-37: Fix handleTunnelConnect and tunnelTarget so a plain box ID
from the Host header cannot authorize a tunnel: require and validate a securely
signed preview token or restored Proxy-Authorization/ticket credential, reject
decoding or validation failures, and verify the requested port is marked public
before calling getBoxRunnerInfo or dialing the runner.
- Line 63: Update the tunnel setup around proxyTunnelStreams to wrap clientConn
with bufferedConn, matching the existing runner connection handling, and pass
the wrapped client connection into proxyTunnelStreams so bytes already held by
hijacker.Hijack’s buffered.Reader are forwarded.

---

Outside diff comments:
In `@apps/proxy/pkg/proxy/tunnel.go`:
- Around line 117-123: Update the CONNECT request construction near req.Host so
http.NewRequestWithContext receives only path rather than "http://"+host+path,
then retain host in req.Host. Preserve the existing context, method, error
cleanup, and escaped tunnel path so req.Write sends the full path as the
Request-URI.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 18693219-6bf9-4a71-8f2e-fb66e2643ec1

📥 Commits

Reviewing files that changed from the base of the PR and between dda5848 and 18617ec.

📒 Files selected for processing (9)
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.spec.ts
  • apps/api/src/boxlite-rest/boxlite-proxy.controller.ts
  • apps/infra/sst.config.ts
  • apps/proxy/pkg/proxy/proxy.go
  • apps/proxy/pkg/proxy/tunnel.go
  • apps/proxy/pkg/proxy/tunnel_test.go
  • openapi/box.openapi.yaml
  • src/boxlite/src/rest/client.rs
  • src/boxlite/src/rest/litebox.rs
💤 Files with no reviewable changes (2)
  • apps/proxy/pkg/proxy/proxy.go
  • apps/infra/sst.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/boxlite/src/rest/litebox.rs

Comment thread apps/proxy/pkg/proxy/tunnel.go
Comment thread apps/proxy/pkg/proxy/tunnel.go Outdated
@coderabbitai coderabbitai Bot mentioned this pull request Jul 21, 2026
3 tasks
@G4614

G4614 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Split into #992 (core/OpenAPI), #994 (SDKs and SDK E2E), and #995 (API/proxy/runner); all three branches are rebuilt from the latest main.

@G4614 G4614 closed this Jul 21, 2026
auto-merge was automatically disabled July 21, 2026 22:53

Pull request was closed

@G4614 G4614 reopened this Jul 22, 2026
@G4614
G4614 marked this pull request as draft July 22, 2026 04:13
@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@G4614
G4614 force-pushed the codex/runner-guest-port-connect branch from 894039b to 8f50bcd Compare July 22, 2026 08:59
@G4614
G4614 force-pushed the codex/runner-guest-port-connect branch from 8f50bcd to 75751a9 Compare July 23, 2026 05:09
@G4614 G4614 closed this Jul 23, 2026
@G4614
G4614 force-pushed the codex/runner-guest-port-connect branch from 75751a9 to b1ba38a Compare July 23, 2026 05:16
@G4614 G4614 reopened this Jul 23, 2026
@G4614
G4614 force-pushed the codex/runner-guest-port-connect branch from 1182eb8 to ae6a01e Compare July 23, 2026 05:54
@G4614 G4614 changed the title refactor(tunnel): route SDK streams through HTTP CONNECT fix(sdk): preserve tunnel half-close responses Jul 23, 2026
@G4614 G4614 closed this Jul 23, 2026
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