Skip to content

Add team-vault credential leases with local egress - #99

Merged
lawrencecchen merged 38 commits into
mainfrom
feat/client-failover
Jul 29, 2026
Merged

lawrencecchen merged 38 commits into
mainfrom
feat/client-failover

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Replaces the shared-Mac data plane with a loopback proxy on every macOS or Linux client. cmux.com chooses a shared team account and returns a five-minute access-only lease. The local daemon sends the provider request from that client machine. Provider refresh tokens stay central.

Refresh custody

  • Upload and repair force one central refresh before success, adopting the current rotation chain.
  • Refreshes are single-flight per account.
  • Successful rotation atomically stores the next access, refresh, and ID tokens before leasing.
  • invalid_grant is terminal. Transport failures and malformed success responses are ambiguous, freeze the account, and never retry the old refresh token.
  • Stale lease generations cannot mutate a repaired credential chain.
  • Leases reject refresh tokens, ID tokens, API-key fields, and credential objects at the Go client boundary.

Local data plane and CLI

  • sr login, sr logout, sr team list|use, and sr account list|import|repair|delete.
  • sr setup, sr doctor, sr cleanup, and sr daemon start|stop|restart|status|logs.
  • sr codex and sr claude auto-start and use the loopback daemon in team-vault mode.
  • The daemon authenticates provider routes with the signed-in Stack session, which protects shared Linux hosts.
  • Cloud mode fails closed. It never uses legacy remote routing, local refresh stores, Bedrock, or personal API-key fallback.
  • Bulk import requires dry-run review plus --all --yes; rollout starts with one exact canary account.

The cmux.com API is manaflow-ai/cmux#9099.

Deployment and canary

  • Production Worker: version 467267f5-fb1c-4d25-bacc-730a566a42ff at subrouter.cmux.dev.
  • Staging Worker: version de30e48e-aa7d-4bb1-8704-a27dcd9d2e71 at subrouter-staging.cmux.dev.
  • Durable web staging: https://cmux-staging.vercel.app
  • Real OpenAI canary returned exactly OK through this Mac's local daemon. Central status remained healthy with no refresh failure.

Verification

  • go test ./... -count=1
  • Worker bun test (50 pass)
  • Worker bun run typecheck

Summary by CodeRabbit

  • New Features
    • Added cloud sign-in, team selection, credential storage, shared account import, repair, and extended setup/doctor/cleanup workflows.
    • Added local daemon lifecycle commands (up/down/restart/status), log streaming, and OS-specific health reporting.
    • Implemented authenticated Codex/Claude local-proxy launching with secure secret inputs.
    • Added health-based failover between configured servers and the local daemon, including pin/disable/override behavior.
  • Bug Fixes
    • Hardened credential refresh classification, health probing, and proxy/failover decisions to reduce misrouting and secret leakage.
  • Documentation
    • Documented local egress credential leasing model and invariants.
  • Tests
    • Added/expanded coverage for failover, leasing, lifecycle, cloud-mode routing, and CLI usage/help output.

A wedged Subrouter host takes every client with it. When cmux-mac-mini
exhausted its kernel mbuf pool, it stopped accepting TCP entirely while
still answering ICMP, so `sr codex` handed codex a base URL that silently
hung instead of failing. Every machine on the team was blocked even though
each had a healthy daemon on 127.0.0.1:31415 the whole time.

Probe the configured server's /_subrouter/health before launching codex and
substitute the local daemon when it does not answer. The probe is bounded at
1.5s because a buffer-exhausted host drops SYNs rather than refusing them, so
an unbounded dial would hang rather than fail over.

Resolution stays pure: defaultCodexBaseURLFor does no network I/O, and the
probe runs only on the launch path in codexBaseURLWithFallback. An explicit
SUBROUTER_CODEX_BASE_URL or SUBROUTER_CODEX_SERVER is a deliberate pin and is
never overridden; SUBROUTER_DISABLE_FALLBACK opts out entirely.

Also add sr up/down/restart/health, wrapping the launchd and systemd units
that install-daemon and install-systemd already write, so restarting the
server does not mean remembering launchctl bootout incantations. These are
local-only commands and are never forwarded to a remote server.
@coderabbitai

coderabbitai Bot commented Jul 28, 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

Adds cloud credential leasing and refresh-repair handling, broker-backed proxy authorization, local daemon installation and lifecycle commands, health-based fallback routing, and cloud-aware Codex/Claude CLI behavior.

Changes

Cloud credential leasing and proxy integration

Layer / File(s) Summary
Broker configuration and lease client
internal/broker/..., cloudflare/packages/worker/src/contract.ts
Adds credential-source configuration, secure persistence, broker API methods, lease caching and validation, credential-generation tracking, and blocking refresh-failure classification.
Durable-object lease lifecycle
cloudflare/packages/worker/src/index.ts, cloudflare/packages/worker/test/...
Adds tenant lease issuance and event APIs, centralized refresh, blocked-account routing, credential adoption, repair, lease invalidation, and related coverage.
Credential-broker proxy flow
internal/proxy/..., cmd/subrouter/main.go
Routes proxy requests through broker leases, authorizes local proxy tokens, reports HTTP/WebSocket outcomes, disables local-secret fallback, and fails closed on broker errors.
Cloud CLI and agent routing
cmd/subrouter/sr_cloud.go, cmd/subrouter/sr.go, cmd/subrouter/sr_claude.go, cmd/subrouter/codex.go
Adds cloud login, setup, team/account operations, credential-source-aware dispatch, local Claude proxy launching, and authenticated Codex provider configuration.
Daemon lifecycle and fallback routing
cmd/subrouter/lifecycle.go, cmd/subrouter/sr_setup.go, cmd/subrouter/serverfallback.go, cmd/subrouter/install_systemd_user.go, cmd/subrouter/sr_daemon.go
Adds platform-specific service control, user systemd installation, setup/cleanup/doctor commands, health probing, daemon autostart, and configured-server fallback behavior.
CLI help, telemetry, and documentation
cmd/subrouter/main.go, cmd/subrouter/sr_server.go, cloudflare/packages/worker/src/telemetry.ts, docs/local-egress.md, cloudflare/packages/worker/README.md
Updates command help and server aliases, records new tenant route patterns, and documents local egress lease and repair semantics.

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

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.37% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: team-vault credential leases with local egress.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/client-failover

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.

@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: 3

🤖 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 `@cmd/subrouter/lifecycle.go`:
- Around line 164-177: Update defaultCodexBaseURLForHealth to resolve
SUBROUTER_CODEX_BASE_URL and SUBROUTER_CODEX_SERVER overrides before loading the
persisted default server, returning the explicitly selected endpoint when either
is set. Preserve the existing stored-default fallback when no override is
configured, and do not apply failover during health reporting.

In `@cmd/subrouter/serverfallback.go`:
- Around line 118-120: Remove the configured URL values from the warning emitted
by the fallback logic around the warn check. Keep the message generic, or pass
both baseURL and local through the project’s established redaction helper before
formatting them, ensuring credentials and query parameters cannot reach
stderr/log capture.
- Around line 46-52: Update sameEndpoint to compare parsed schemes as well as
hosts, using a case-insensitive comparison for both components. Return false
when either scheme or host differs, so HTTP and HTTPS endpoints remain distinct
while preserving the existing invalid-URL 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: 7a31ad9e-7ea2-4372-8518-e412cb01f71b

📥 Commits

Reviewing files that changed from the base of the PR and between f571beb and dc9a0c5.

📒 Files selected for processing (5)
  • cmd/subrouter/codex.go
  • cmd/subrouter/lifecycle.go
  • cmd/subrouter/serverfallback.go
  • cmd/subrouter/serverfallback_test.go
  • cmd/subrouter/sr.go

Comment thread cmd/subrouter/lifecycle.go
Comment thread cmd/subrouter/serverfallback.go Outdated
Comment thread cmd/subrouter/serverfallback.go
The CLI had no answer to "is this thing working?" During today's outage the
only way to tell a wedged server from a routing problem was curl against
/_subrouter/health by hand.

sr doctor reports the checks in the order a failure bites: daemon installed,
daemon healthy, configured server healthy, accounts present. It distinguishes
a server that is down but covered by local fallback (warn) from one that is
down with no fallback (fail), and exits non-zero only on the latter so it can
gate scripts.

sr setup is idempotent onboarding: install the daemon, start it, wait for
health, then print the one useful next step. sr cleanup prints its plan and
does nothing without --yes; credentials survive unless --purge, because
losing a refresh-token chain means re-running OAuth for every account.

Lifecycle moves under sr server up/down/restart, matching the noun the verbs
act on, and sr server status with no name now reports this machine rather
than erroring. Both controllers gained remove(), and cleanup and doctor take
an injected controller so tests do not depend on the host's launchd state.

directSRCommands gains the three new verbs so they work when the binary is
invoked as subrouter or cx, not only as sr, with main_test.go's guard list
updated to match.
@lawrencecchen lawrencecchen changed the title Fail over to the local daemon when the configured server is unreachable Resilient routing: local failover, plus sr setup / doctor / cleanup and sr server up|down Jul 28, 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.

🧹 Nitpick comments (2)
cmd/subrouter/sr_server.go (1)

109-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add test coverage for the new lifecycle dispatch.

up/start, down/stop, restart, and the arg-count-based status branching are new dispatch logic, but no test changes for sr_server.go are included in this cohort. Consider adding cases exercising each alias and both status (no name → local health) and status <name> (remote) paths.

🤖 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 `@cmd/subrouter/sr_server.go` around lines 109 - 124, Add table-driven tests
for the lifecycle dispatch in the server subrouter, covering both up/start and
down/stop aliases, restart, and status with no name versus a named server.
Assert that no-name status invokes local health and status with a name invokes
the remote server-status path, while preserving the existing argument validation
behavior.
cmd/subrouter/sr_setup_test.go (1)

100-134: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add doctor coverage for the "configured server" reachable/fallback/fail branches.

Existing tests only exercise the configured == "" (local) path in runDoctorWith's configured-server check. The reachable-remote, fallback-warn, and no-fallback-fail branches (sr_setup.go lines 203-209) are untested, even though doctor's exit code is used to gate scripts.

🤖 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 `@cmd/subrouter/sr_setup_test.go` around lines 100 - 134, Add tests for
runDoctorWith covering a configured server that is reachable, unreachable with a
usable local fallback, and unreachable without a fallback. Configure the server
URL and health responses to assert successful continuation for the reachable
case, a warning for fallback, and an error/failure result when no fallback
exists, including the expected output and doctor status.
🤖 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.

Nitpick comments:
In `@cmd/subrouter/sr_server.go`:
- Around line 109-124: Add table-driven tests for the lifecycle dispatch in the
server subrouter, covering both up/start and down/stop aliases, restart, and
status with no name versus a named server. Assert that no-name status invokes
local health and status with a name invokes the remote server-status path, while
preserving the existing argument validation behavior.

In `@cmd/subrouter/sr_setup_test.go`:
- Around line 100-134: Add tests for runDoctorWith covering a configured server
that is reachable, unreachable with a usable local fallback, and unreachable
without a fallback. Configure the server URL and health responses to assert
successful continuation for the reachable case, a warning for fallback, and an
error/failure result when no fallback exists, including the expected output and
doctor status.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0eab0ea2-8174-493f-ad26-f5f0b754428f

📥 Commits

Reviewing files that changed from the base of the PR and between dc9a0c5 and f271cf4.

📒 Files selected for processing (7)
  • cmd/subrouter/lifecycle.go
  • cmd/subrouter/main.go
  • cmd/subrouter/main_test.go
  • cmd/subrouter/sr.go
  • cmd/subrouter/sr_server.go
  • cmd/subrouter/sr_setup.go
  • cmd/subrouter/sr_setup_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/subrouter/lifecycle.go

A cold machine had to run `sr server up` before `sr codex` would work, which
is a step nobody remembers and the error it produced (a hung dial) did not
explain. Launching an agent now starts the daemon when nothing is serving.

Ordering matters and is deliberate: a healthy configured server always wins,
so autostart only runs when nothing already answers. That keeps the common
case free of extra probes and avoids starting a local daemon that would go
unused.

Autostart also runs when the configured target *is* this machine's daemon,
including under SUBROUTER_DISABLE_FALLBACK, because starting it repairs the
configured target rather than substituting a different one. Pinning via
SUBROUTER_CODEX_BASE_URL still never redirects traffic elsewhere.

For Claude, only the launching forms trigger it; `sr claude list` and the
other management subcommands stay quiet.

Also fixes help drift found while dogfooding: `sr help` renders usageText in
main.go, not the srHelp const, so the new commands were missing from the help
users actually see. Both surfaces now list them and a test asserts it.
@lawrencecchen lawrencecchen changed the title Resilient routing: local failover, plus sr setup / doctor / cleanup and sr server up|down Add team-vault credential leases with local egress Jul 29, 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: 11

Caution

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

⚠️ Outside diff range comments (2)
cloudflare/packages/worker/src/contract.ts (1)

690-713: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Preserve terminal refresh signals from standard OAuth error fields.

Dropping the response body means object-form OAuth refresh errors can become non-terminal when the signal lives in error or error_description rather than providerCode/providerType. For example, {"error":{"message":"invalid_grant: refresh token revoked"}} currently returns provider rejected the refresh with no providerCode, so terminalRefreshFailure can fail to block refresh indefinitely and replay a rotated refresh token. Extract error/error_description as OAuth standard fields and match them against a known-code allowlist instead of persisting the raw body.

🤖 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 `@cloudflare/packages/worker/src/contract.ts` around lines 690 - 713, Update
refreshError to extract OAuth standard error and error_description fields from
parsed provider responses, including nested object messages, and match those
values against the existing known terminal-error allowlist used by
terminalRefreshFailure. Populate the appropriate providerCode or equivalent
terminal signal without persisting the raw response body, while preserving the
current status-based error message and sanitized error properties.
cmd/subrouter/codex.go (1)

20-28: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Gate localProxyToken on the resolved baseURL.

codexBaseURLWithFallback returns a pinned baseURL unchanged, while cloudLocalProxyToken(cloudConfig) returns the stored access token whenever cloud config is team-ready. If a user has team/local credential storage configured and sets SUBROUTER_CODEX_BASE_URL or SUBROUTER_CODEX_SERVER to a non-local endpoint, codex still writes that token into SUBROUTER_CODEX_DUMMY_API_KEY and sends it as the Subrouter bearer credential to the pinned endpoint. Derive localProxyToken only when baseURL matches the local daemon endpoint (or not attach the token for unpinned remote fallbacks).

🤖 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 `@cmd/subrouter/codex.go` around lines 20 - 28, Update the localProxyToken
derivation in the codex setup flow to depend on the resolved baseURL: only call
cloudLocalProxyToken when baseURL matches the local daemon endpoint, and
otherwise leave the token unset so it is not attached to pinned or remote
endpoints. Preserve the existing cloud configuration error handling and baseURL
resolution.
🧹 Nitpick comments (5)
cmd/subrouter/sr_cloud.go (2)

683-717: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Substring fallback matching can select the wrong credential.

selectLocalAccountUpload falls back to strings.Contains matching; --only work silently resolves to work-backup when only one partial match exists. For an operation that uploads credentials to a shared vault, prefer requiring an exact label or kind:label match.

🤖 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 `@cmd/subrouter/sr_cloud.go` around lines 683 - 717, Update
selectLocalAccountUpload to remove substring fallback matching via
strings.Contains and consider only exact label or kind:label matches. Preserve
the existing empty-selector, not-found, and ambiguous-match errors, ensuring
selectors like “work” do not resolve to labels such as “work-backup”.

73-77: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

A single transient poll error aborts the whole login.

Any network blip or 5xx from /auth/poll fails the command and forces the user to restart device approval. Tolerate transient errors until the deadline.

♻️ Suggested change
 		case <-ticker.C:
 			poll, err = client.PollAuth(ctx, start.DeviceCode)
 			if err != nil {
-				return fmt.Errorf("poll cmux.com login: %w", err)
+				// Transient broker/network errors must not cancel an
+				// approval the user may already be completing.
+				continue
 			}
🤖 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 `@cmd/subrouter/sr_cloud.go` around lines 73 - 77, Update the PollAuth handling
in the ticker.C branch of the device-login polling loop so transient network or
5xx errors are tolerated and polling continues until the existing deadline. Do
not return immediately from this branch; retain the last error as needed and
only return a failure when the context/deadline expires, while preserving
successful poll handling.
cmd/subrouter/main.go (1)

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

Collapse the two team-mode preconditions.

The second check (Team && !Ready()) already subsumes the first (Team && LoggedIn && TeamID == ""); only the message differs. Keeping both invites drift.

♻️ Suggested simplification
-	if cloudConfig.EffectiveCredentialSource() == broker.CredentialSourceTeam &&
-		cloudConfig.LoggedIn() &&
-		cloudConfig.TeamID == "" {
-		return errors.New("cmux.com login has no selected team; run 'sr team use <team>'")
-	}
-	if cloudConfig.EffectiveCredentialSource() == broker.CredentialSourceTeam &&
-		!cloudConfig.Ready() {
-		return errors.New("team credential storage requires login and a selected team; run 'sr login'")
-	}
+	if cloudConfig.EffectiveCredentialSource() == broker.CredentialSourceTeam && !cloudConfig.Ready() {
+		if cloudConfig.LoggedIn() {
+			return errors.New("cmux.com login has no selected team; run 'sr team use <team>'")
+		}
+		return errors.New("team credential storage requires login and a selected team; run 'sr login'")
+	}
🤖 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 `@cmd/subrouter/main.go` around lines 253 - 265, The two team-mode validation
branches in the config-loading flow should be collapsed into a single
`CredentialSourceTeam && !cloudConfig.Ready()` check. Remove the redundant
`LoggedIn()`/`TeamID` condition and preserve the more specific selected-team
error message only if the existing readiness error cannot provide the required
behavior; otherwise retain one consistent error message.
cmd/subrouter/sr_claude.go (1)

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

Remove the unused cloudClaude method.

cloudClaude is defined but no code calls it; the sr claude launch path already inlines the team-mode readiness check before proxyClaude. Keeping it only adds unreachable code.

🤖 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 `@cmd/subrouter/sr_claude.go` around lines 99 - 111, Remove the unused
srRunner.cloudClaude method, including its associated comment, while preserving
the existing sr claude launch path and its inlined team-mode readiness check
before proxyClaude.
cmd/subrouter/install_systemd_user.go (1)

50-61: 🩺 Stability & Availability | 🔵 Trivial

Consider enabling linger so the daemon survives logout.

systemctl --user enable --now starts the unit, but on most distros a systemd --user manager (and its services) is stopped when the user's last session ends unless loginctl enable-linger <user> has been run. Since this daemon is meant to run continuously as a background credential proxy, installation should check/enable lingering (or clearly warn the user it's required) so the loopback proxy doesn't silently disappear after logout/SSH disconnect.

#!/bin/bash
# Confirm whether linger enablement is handled elsewhere in the daemon lifecycle code.
rg -n -i 'linger' --type=go
🤖 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 `@cmd/subrouter/install_systemd_user.go` around lines 50 - 61, Update the
installation flow surrounding the systemd user-unit setup to ensure user
lingering is enabled before or alongside the existing daemon-reload and enable
--now commands. Use the existing command runner and current-user context to
invoke loginctl enable-linger for the installing user, or provide an explicit
warning if the project handles this elsewhere; avoid duplicating the change if
an existing linger lifecycle helper is available.
🤖 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 `@cloudflare/packages/worker/src/index.ts`:
- Around line 1904-1911: Update the credential-expiry handling in the route flow
around credentialExpiresAt and isOAuthKind so an OAuth credential expiring
within the lease window is marked frozen/deprioritized using the same mechanism
as the blocking-refresh case near line 1879, then re-route instead of throwing
immediately. Preserve the existing hard-failure behavior only when no eligible
credential remains.

In `@cmd/subrouter/codex.go`:
- Around line 102-111: Update the pinned-endpoint branch around
ensureLocalHealthy so its failure result is checked and converted into the same
clear “local proxy is unavailable; run '%s doctor'” diagnostic used by the
equivalent unpinned path. Preserve returning baseURL on successful health checks
and keep non-local pinned endpoints unchanged.

In `@cmd/subrouter/install_systemd_user.go`:
- Around line 15-65: Update installUserSystemd to accept the caller-provided
io.Writer and write the three confirmation messages through it instead of
fmt.Printf; update runSetup and all other call sites to pass their existing out
writer, preserving the current message content.

In `@cmd/subrouter/serverfallback_test.go`:
- Around line 186-211: Replace the shared healthy state in
TestEnsureLocalHealthyStartsDeadDaemon and the corresponding test at
cmd/subrouter/serverfallback_test.go lines 239-261 with atomic.Bool; use Load in
each HTTP handler and Store(true) in each start callback, preserving existing
behavior. Run go test ./... before handing off.

In `@cmd/subrouter/sr_claude_upload.go`:
- Around line 41-52: Replace the hardcoded “sr” command name in the team-storage
and local-storage error messages within the credential-source switch with the
dynamic name returned by r.programOrSubrouter(), matching the guidance behavior
later in the function. Preserve the existing message content and
credential-source handling.

In `@cmd/subrouter/sr_cloud.go`:
- Around line 126-131: The cloudLocalProxyToken flow must stop returning
config.AccessToken, since that session token is exposed to agent processes.
Generate and persist a separate random loopback-only bearer secret in the daemon
state directory, return it for LocalProxyToken, and validate proxy requests
against that secret while preserving the existing TeamModeReady gating.
- Around line 447-459: Update the anthropic-key handling in the relevant
subrouter command to read the API key through the existing no-echo secret-input
mechanism instead of promptLine, while retaining promptLine for the
non-sensitive label and preserving the current sk-ant- prefix validation.

In `@cmd/subrouter/sr_setup.go`:
- Around line 258-284: Update the “provider egress” checks in the team-ready and
local-credential branches to use the existing localOK result instead of
unconditionally reporting “ok.” Preserve the current success message when
localOK is true, and report a failing doctorCheck with the local daemon failure
details when it is false, keeping the output consistent with the earlier local
daemon check.

In `@cmd/subrouter/sr.go`:
- Around line 168-172: Update the command dispatch flow around cloudModeConfig
so configuration-load errors do not block the recovery/local verbs help, doctor,
cleanup, login, logout, storage, and setup; allow those commands to dispatch
without a loaded config, while preserving the existing “load credential storage”
error for other commands that require valid configuration.

In `@internal/broker/client_test.go`:
- Around line 39-40: Remove credential-bearing diagnostics from all three
assertions in internal/broker/client_test.go: at lines 39-40 replace the loaded
configuration dump with a generic failure message; at lines 198-203 split the
conditions and report failures without formatting err; at lines 286-292 report
the leak generically without printing err. Preserve the existing assertion
behavior while ensuring no sensitive fixture, error, token, key, request body,
or authorization data is emitted.

In `@internal/broker/client.go`:
- Around line 283-286: Update the cache replacement logic around the lease
assignment to remove the previous lease’s entry from leaseToKey before storing
the new lease mapping. Preserve the existing cache[key] and current lease-to-key
assignments, and ensure the cleanup only removes the superseded mapping when a
prior cached lease exists.

---

Outside diff comments:
In `@cloudflare/packages/worker/src/contract.ts`:
- Around line 690-713: Update refreshError to extract OAuth standard error and
error_description fields from parsed provider responses, including nested object
messages, and match those values against the existing known terminal-error
allowlist used by terminalRefreshFailure. Populate the appropriate providerCode
or equivalent terminal signal without persisting the raw response body, while
preserving the current status-based error message and sanitized error
properties.

In `@cmd/subrouter/codex.go`:
- Around line 20-28: Update the localProxyToken derivation in the codex setup
flow to depend on the resolved baseURL: only call cloudLocalProxyToken when
baseURL matches the local daemon endpoint, and otherwise leave the token unset
so it is not attached to pinned or remote endpoints. Preserve the existing cloud
configuration error handling and baseURL resolution.

---

Nitpick comments:
In `@cmd/subrouter/install_systemd_user.go`:
- Around line 50-61: Update the installation flow surrounding the systemd
user-unit setup to ensure user lingering is enabled before or alongside the
existing daemon-reload and enable --now commands. Use the existing command
runner and current-user context to invoke loginctl enable-linger for the
installing user, or provide an explicit warning if the project handles this
elsewhere; avoid duplicating the change if an existing linger lifecycle helper
is available.

In `@cmd/subrouter/main.go`:
- Around line 253-265: The two team-mode validation branches in the
config-loading flow should be collapsed into a single `CredentialSourceTeam &&
!cloudConfig.Ready()` check. Remove the redundant `LoggedIn()`/`TeamID`
condition and preserve the more specific selected-team error message only if the
existing readiness error cannot provide the required behavior; otherwise retain
one consistent error message.

In `@cmd/subrouter/sr_claude.go`:
- Around line 99-111: Remove the unused srRunner.cloudClaude method, including
its associated comment, while preserving the existing sr claude launch path and
its inlined team-mode readiness check before proxyClaude.

In `@cmd/subrouter/sr_cloud.go`:
- Around line 683-717: Update selectLocalAccountUpload to remove substring
fallback matching via strings.Contains and consider only exact label or
kind:label matches. Preserve the existing empty-selector, not-found, and
ambiguous-match errors, ensuring selectors like “work” do not resolve to labels
such as “work-backup”.
- Around line 73-77: Update the PollAuth handling in the ticker.C branch of the
device-login polling loop so transient network or 5xx errors are tolerated and
polling continues until the existing deadline. Do not return immediately from
this branch; retain the last error as needed and only return a failure when the
context/deadline expires, while preserving successful poll 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: fdbef0fc-f3b8-4473-bf00-f64a0eb88a11

📥 Commits

Reviewing files that changed from the base of the PR and between f271cf4 and 10fa100.

📒 Files selected for processing (28)
  • cloudflare/packages/worker/README.md
  • cloudflare/packages/worker/src/contract.ts
  • cloudflare/packages/worker/src/index.ts
  • cloudflare/packages/worker/src/telemetry.ts
  • cloudflare/packages/worker/test/contract.test.ts
  • cloudflare/packages/worker/test/credential-lease.test.ts
  • cmd/subrouter/cloud_mode_test.go
  • cmd/subrouter/codex.go
  • cmd/subrouter/install_systemd_user.go
  • cmd/subrouter/lifecycle.go
  • cmd/subrouter/main.go
  • cmd/subrouter/main_test.go
  • cmd/subrouter/serverfallback.go
  • cmd/subrouter/serverfallback_test.go
  • cmd/subrouter/sr.go
  • cmd/subrouter/sr_claude.go
  • cmd/subrouter/sr_claude_upload.go
  • cmd/subrouter/sr_cloud.go
  • cmd/subrouter/sr_daemon.go
  • cmd/subrouter/sr_server.go
  • cmd/subrouter/sr_setup.go
  • cmd/subrouter/sr_setup_test.go
  • docs/local-egress.md
  • internal/broker/client.go
  • internal/broker/client_test.go
  • internal/broker/config.go
  • internal/proxy/credential_broker_test.go
  • internal/proxy/proxy.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • cmd/subrouter/sr_setup_test.go
  • cmd/subrouter/sr_server.go
  • cmd/subrouter/lifecycle.go

Comment thread cloudflare/packages/worker/src/index.ts
Comment thread cmd/subrouter/codex.go Outdated
Comment thread cmd/subrouter/install_systemd_user.go Outdated
Comment thread cmd/subrouter/serverfallback_test.go
Comment thread cmd/subrouter/sr_claude_upload.go
Comment thread cmd/subrouter/sr_cloud.go
Comment thread cmd/subrouter/sr_setup.go
Comment thread cmd/subrouter/sr.go
Comment thread internal/broker/client_test.go Outdated
Comment thread internal/broker/client.go

@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: 3

♻️ Duplicate comments (1)
cmd/subrouter/sr_cloud.go (1)

469-481: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Two secret-entry prompts in sr_cloud.go echo API keys to the terminal. Both call promptLine, which has no echo-suppression, for reading sensitive API keys — the root cause is the shared lack of a no-echo secret-input helper.

  • cmd/subrouter/sr_cloud.go#L469-L481: switch the anthropic-key prompt ("Anthropic API key (sk-ant-...): ") to a no-echo reader (e.g. golang.org/x/term.ReadPassword), keeping promptLine only for the non-sensitive label.
  • cmd/subrouter/sr_cloud.go#L611-L657: switch the "Replacement API key for %s: " prompt in replacementUploadForSharedAccount to the same no-echo reader.
🤖 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 `@cmd/subrouter/sr_cloud.go` around lines 469 - 481, The secret API-key prompts
currently use echoing input; update the anthropic-key flow in
cmd/subrouter/sr_cloud.go lines 469-481 to keep promptLine for the label but
read the key with a shared no-echo helper based on terminal password input,
preserving validation. Apply the same no-echo reader to the
replacementUploadForSharedAccount prompt in cmd/subrouter/sr_cloud.go lines
611-657, reusing the helper rather than introducing separate implementations.
🧹 Nitpick comments (2)
cloudflare/packages/worker/test/credential-lease.test.ts (1)

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

Document why the replacement-refresh wait is bounded.

Promise.race with Bun.sleep(50) means the intended interleaving isn't guaranteed on a loaded runner — the final assertion still passes either way, so a lost race silently weakens the test rather than failing it. A short comment noting the timeout exists to avoid hanging when the replacement refresh never fires would keep that tradeoff visible.

🤖 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 `@cloudflare/packages/worker/test/credential-lease.test.ts` around lines 634 -
638, Document the bounded wait around Promise.race in the replacement-refresh
test, explaining that Bun.sleep(50) prevents the test from hanging if
replacementRefreshStarted never fires, while acknowledging the intended
interleaving may not be guaranteed under load.
cmd/subrouter/sr_cloud.go (1)

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

Duplicated AccountUpload map construction for API-key providers.

Both the anthropic-key direct-add path and replacementUploadForSharedAccount build the same {"provider","label","apiKey"} map shape. Consider extracting a small apiKeyAccountUpload(kind, label, key string) broker.AccountUpload helper to keep the two call sites in sync.

Also applies to: 652-656

🤖 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 `@cmd/subrouter/sr_cloud.go` around lines 482 - 486, The API-key AccountUpload
map is duplicated between the anthropic direct-add path and
replacementUploadForSharedAccount. Extract an apiKeyAccountUpload(kind, label,
key string) broker.AccountUpload helper, then use it at both construction sites
while preserving provider, label, and trimmed apiKey values.
🤖 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 `@cmd/subrouter/lifecycle_test.go`:
- Around line 21-39: The test’s wait callback must verify success output has not
been written before readiness is checked. Update
TestRestartWaitsForDaemonHealthBeforeReportingSuccess so waitForReady asserts
that out is empty (or records and validates an equivalent event sequence), while
preserving the existing health-check count and final output assertions.

In `@cmd/subrouter/main.go`:
- Around line 270-273: Update serve so TeamModeReady enforces a closed
credential boundary before server construction: reject or bypass the
unconditional Bedrock setup and disable personal API-key fallback, including
SUBROUTER_CLAUDE_FABLE_API_KEY. Ensure the proxy.Server configuration clears the
corresponding legacy credential fields in team mode while preserving normal
credential behavior outside team mode.

In `@internal/broker/client_test.go`:
- Around line 170-178: Update the httptest server handler in the relevant client
test to avoid calling t.Fatal or t.Fatalf from its goroutine; capture handler
decode and assertion failures in a thread-safe result or error value, then
assert on the main test goroutine after the request completes. Preserve the
existing request validation and run go test ./... before handoff.

---

Duplicate comments:
In `@cmd/subrouter/sr_cloud.go`:
- Around line 469-481: The secret API-key prompts currently use echoing input;
update the anthropic-key flow in cmd/subrouter/sr_cloud.go lines 469-481 to keep
promptLine for the label but read the key with a shared no-echo helper based on
terminal password input, preserving validation. Apply the same no-echo reader to
the replacementUploadForSharedAccount prompt in cmd/subrouter/sr_cloud.go lines
611-657, reusing the helper rather than introducing separate implementations.

---

Nitpick comments:
In `@cloudflare/packages/worker/test/credential-lease.test.ts`:
- Around line 634-638: Document the bounded wait around Promise.race in the
replacement-refresh test, explaining that Bun.sleep(50) prevents the test from
hanging if replacementRefreshStarted never fires, while acknowledging the
intended interleaving may not be guaranteed under load.

In `@cmd/subrouter/sr_cloud.go`:
- Around line 482-486: The API-key AccountUpload map is duplicated between the
anthropic direct-add path and replacementUploadForSharedAccount. Extract an
apiKeyAccountUpload(kind, label, key string) broker.AccountUpload helper, then
use it at both construction sites while preserving provider, label, and trimmed
apiKey values.
🪄 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: ae677267-8572-4e6d-9c36-4a0cf5cb7600

📥 Commits

Reviewing files that changed from the base of the PR and between 10fa100 and 1dbb4c6.

📒 Files selected for processing (27)
  • cloudflare/packages/worker/src/contract.ts
  • cloudflare/packages/worker/src/index.ts
  • cloudflare/packages/worker/test/contract.test.ts
  • cloudflare/packages/worker/test/credential-lease.test.ts
  • cmd/subrouter/cloud_mode_test.go
  • cmd/subrouter/codex.go
  • cmd/subrouter/install_daemon.go
  • cmd/subrouter/install_daemon_test.go
  • cmd/subrouter/install_systemd_test.go
  • cmd/subrouter/install_systemd_user.go
  • cmd/subrouter/lifecycle.go
  • cmd/subrouter/lifecycle_test.go
  • cmd/subrouter/main.go
  • cmd/subrouter/main_test.go
  • cmd/subrouter/serverfallback.go
  • cmd/subrouter/serverfallback_test.go
  • cmd/subrouter/sr.go
  • cmd/subrouter/sr_claude.go
  • cmd/subrouter/sr_claude_test.go
  • cmd/subrouter/sr_cloud.go
  • cmd/subrouter/sr_setup.go
  • cmd/subrouter/sr_setup_test.go
  • internal/broker/client.go
  • internal/broker/client_test.go
  • internal/broker/config.go
  • internal/proxy/credential_broker_test.go
  • internal/proxy/proxy.go
🚧 Files skipped from review as they are similar to previous changes (13)
  • cloudflare/packages/worker/test/contract.test.ts
  • cmd/subrouter/install_systemd_user.go
  • cmd/subrouter/serverfallback.go
  • cmd/subrouter/sr_claude.go
  • internal/broker/config.go
  • cmd/subrouter/sr_setup_test.go
  • cmd/subrouter/sr_setup.go
  • cmd/subrouter/codex.go
  • cloudflare/packages/worker/src/contract.ts
  • cmd/subrouter/lifecycle.go
  • internal/proxy/proxy.go
  • cmd/subrouter/sr.go
  • cloudflare/packages/worker/src/index.ts

Comment thread cmd/subrouter/lifecycle_test.go
Comment thread cmd/subrouter/main.go
Comment thread internal/broker/client_test.go

@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)
cmd/subrouter/cloud_mode_test.go (1)

467-473: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Assert the read-only bind directive explicitly.

Checking only the path permits a writable mount regression. Expect BindReadOnlyPaths=/home/alice/.codex-accounts exactly.

🤖 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 `@cmd/subrouter/cloud_mode_test.go` around lines 467 - 473, Update the expected
strings in the test around the want list to assert the complete read-only bind
directive for the codex accounts path: use
“BindReadOnlyPaths=/home/alice/.codex-accounts” instead of checking only
“/home/alice/.codex-accounts”.
🤖 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 `@cmd/subrouter/cloud_mode_test.go`:
- Around line 527-533: Update the assertion in the localAccountUploads test to
avoid formatting uploads with %+v, since that exposes apiKey values from
localAccountUpload.body; report only a safe count or non-sensitive summary when
the expected count is wrong. Before handoff, run go test ./....

---

Outside diff comments:
In `@cmd/subrouter/cloud_mode_test.go`:
- Around line 467-473: Update the expected strings in the test around the want
list to assert the complete read-only bind directive for the codex accounts
path: use “BindReadOnlyPaths=/home/alice/.codex-accounts” instead of checking
only “/home/alice/.codex-accounts”.
🪄 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: a3eb52d7-da45-4bc0-803f-9776fd84fab6

📥 Commits

Reviewing files that changed from the base of the PR and between 1dbb4c6 and 7ac1cee.

📒 Files selected for processing (7)
  • cloudflare/packages/worker/src/contract.ts
  • cloudflare/packages/worker/src/index.ts
  • cloudflare/packages/worker/test/contract.test.ts
  • cloudflare/packages/worker/test/credential-lease.test.ts
  • cmd/subrouter/cloud_mode_test.go
  • cmd/subrouter/install_systemd_user.go
  • cmd/subrouter/sr_cloud.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • cloudflare/packages/worker/test/contract.test.ts
  • cmd/subrouter/install_systemd_user.go
  • cloudflare/packages/worker/src/contract.ts
  • cloudflare/packages/worker/test/credential-lease.test.ts
  • cmd/subrouter/sr_cloud.go
  • cloudflare/packages/worker/src/index.ts

Comment thread cmd/subrouter/cloud_mode_test.go
@lawrencecchen
lawrencecchen temporarily deployed to subrouter-staging July 29, 2026 07:25 — with GitHub Actions Inactive
@lawrencecchen
lawrencecchen temporarily deployed to subrouter-staging July 29, 2026 08:10 — with GitHub Actions Inactive
@lawrencecchen
lawrencecchen temporarily deployed to subrouter-staging July 29, 2026 08:17 — with GitHub Actions Inactive
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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

🤖 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 `@cmd/subrouter/cloud_mode_test.go`:
- Around line 76-78: Stop exposing bearer credentials in assertion failures:
update the token checks in cmd/subrouter/cloud_mode_test.go at lines 76-78 and
91-95. At lines 76-78, replace the formatted proxy token with a fixed safe
failure message; at lines 91-95, report only that a non-empty token was returned
without formatting its value.

In `@internal/proxy/proxy.go`:
- Around line 2058-2084: Update credentialLeaseReport so claudeExhaustionExpiry
is used only when provider == accounts.ProviderClaude. For non-Claude
rate-limited providers, derive RetryAt using their provider-appropriate
semantics, such as the Retry-After header, without applying Claude-specific
reset 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: 8dd5bd88-4fdb-4710-9bc2-c9a95621d56a

📥 Commits

Reviewing files that changed from the base of the PR and between 1dbb4c6 and 1bb42c5.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (24)
  • cloudflare/packages/worker/src/contract.ts
  • cloudflare/packages/worker/src/index.ts
  • cloudflare/packages/worker/test/contract.test.ts
  • cloudflare/packages/worker/test/credential-lease.test.ts
  • cmd/subrouter/cloud_mode_test.go
  • cmd/subrouter/codex.go
  • cmd/subrouter/install_systemd_user.go
  • cmd/subrouter/lifecycle_test.go
  • cmd/subrouter/main.go
  • cmd/subrouter/main_test.go
  • cmd/subrouter/serverfallback.go
  • cmd/subrouter/serverfallback_test.go
  • cmd/subrouter/sr.go
  • cmd/subrouter/sr_claude.go
  • cmd/subrouter/sr_claude_upload.go
  • cmd/subrouter/sr_cloud.go
  • cmd/subrouter/sr_server.go
  • cmd/subrouter/sr_setup.go
  • cmd/subrouter/sr_setup_test.go
  • go.mod
  • internal/broker/client.go
  • internal/broker/client_test.go
  • internal/proxy/credential_broker_test.go
  • internal/proxy/proxy.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • cmd/subrouter/lifecycle_test.go
  • cmd/subrouter/sr_claude_upload.go
  • cmd/subrouter/sr_setup.go
  • cmd/subrouter/serverfallback_test.go
  • cmd/subrouter/sr_setup_test.go
  • cmd/subrouter/install_systemd_user.go
  • cmd/subrouter/serverfallback.go
  • cmd/subrouter/codex.go
  • cmd/subrouter/sr.go
  • internal/broker/client_test.go
  • cloudflare/packages/worker/src/contract.ts
  • cmd/subrouter/main.go
  • cmd/subrouter/sr_cloud.go
  • cloudflare/packages/worker/test/contract.test.ts
  • cloudflare/packages/worker/src/index.ts

Comment thread cmd/subrouter/cloud_mode_test.go
Comment thread internal/proxy/proxy.go
@lawrencecchen
lawrencecchen temporarily deployed to subrouter-staging July 29, 2026 08:37 — with GitHub Actions Inactive
@lawrencecchen
lawrencecchen temporarily deployed to subrouter-staging July 29, 2026 08:47 — with GitHub Actions Inactive

This branch was previously deployed

1 inactive deployment
subrouter-staging — 28567893 Deployed Jul 29, 2026 by lawrencecchen via Deploy staging #42
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