feat: extend OPENCLAW_GATEWAY_PRIVATE_INGRESS_NO_AUTH to handshake + role + call paths#6
Merged
shivammittal274 merged 1 commit intobrowserosfrom May 4, 2026
Conversation
…role + call paths Follow-up to #1 (`feat: allow BrowserOS private no-auth gateway images`). That PR relaxed the startup-time bind validation in `server-runtime-config.ts:149` and `gateway-cli/run.ts:813`. The same trust boundary needs to extend to the live handshake and the in-process backend client paths, otherwise BACKEND/GATEWAY_CLIENT calls (e.g. the agent's cron-tool) hit "device identity required" / 1008 even on loopback. This commit closes three remaining gaps, each gated identically on `isLocalClient && allowsGatewayPrivateIngressNoAuth()`: 1. `server/ws-connection/connect-policy.ts` — `evaluateMissingDeviceIdentity` now returns `{ kind: "allow" }` when the connection is loopback and the env flag is set. Closes the 1008 close at `message-handler.ts:713` that the agent's cron tool, channels, and any future backend tool without explicit shared-auth would hit. 2. `role-policy.ts` — `roleCanSkipDeviceIdentity` accepts an optional `isLocalClient` parameter and treats no-auth-loopback as shared-auth-equivalent for operator role. Single call site updated in `connect-policy.ts`. Keeps role and missing-device decisions in sync (otherwise the handshake permits a connection that role policy then blocks downstream). 3. `gateway/call.ts` — `shouldOmitDeviceIdentityForGatewayCall` no longer gates only on `hasSharedAuth`; under no-auth + loopback it also lets the client skip device identity entirely. Defense in depth so that in-process backend tool calls succeed even if `device.json` can't be read (perms, missing dir, subprocess context). Trust boundary unchanged: every relaxation requires `OPENCLAW_GATEWAY_PRIVATE_INGRESS_NO_AUTH=1` AND `isLocalClient` (loopback remote address with no proxy headers). Same posture as the existing patches in #1. Verified: `pnpm tsgo:core` clean. Existing connect-policy and role-policy unit tests (30 cases) all still pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #1. That PR relaxed startup-time bind validation; this PR extends the same trust boundary to the three remaining gates that were still rejecting BrowserOS connections: the live handshake, the role policy, and the in-process backend client.
Without this, BACKEND clients (the agent's cron-tool, channels, anything that uses `callGatewayTool`) hit `"device identity required"` / WS close 1008 even on loopback when running with `OPENCLAW_GATEWAY_PRIVATE_INGRESS_NO_AUTH=1`.
Repro (before this PR)
The agent's `cron-tool` calls `callGateway` (`src/gateway/call.ts`) with `mode=BACKEND, clientName=GATEWAY_CLIENT, no token/password`. `shouldOmitDeviceIdentityForGatewayCall` is gated on `hasSharedAuth` → returns false → the call tries to load `device.json` and connect with a device. The handshake then either: (a) the device file isn't accessible in the in-process backend context and connect goes out without a device, or (b) some path bypasses the device altogether — either way, `message-handler.ts:713` closes with 1008.
What's in this PR
Three changes, each gated identically on `isLocalClient && allowsGatewayPrivateIngressNoAuth()`:
1. `server/ws-connection/connect-policy.ts` — handshake bypass
`evaluateMissingDeviceIdentity` now returns `{ kind: "allow" }` for loopback connections when the env flag is set. Closes the 1008 path.
2. `role-policy.ts` — role bypass
`roleCanSkipDeviceIdentity` accepts an optional `isLocalClient` and treats no-auth-loopback as shared-auth-equivalent for operator role. Keeps role policy and missing-device decisions in sync.
3. `gateway/call.ts` — client-side device omission
`shouldOmitDeviceIdentityForGatewayCall` no longer gates only on `hasSharedAuth`; under no-auth + loopback the backend gateway-client skips device identity entirely. Defense in depth so an in-process backend tool call succeeds even if `device.json` can't be read.
Trust boundary
Unchanged from #1. Every relaxation in this PR requires:
Same posture as your existing `server-runtime-config.ts:149` and `gateway-cli/run.ts:813` bypasses. No remote client gains anything.
Validation
Stats
3 files changed, +34 / −4
```
src/gateway/call.ts | 11 ++++++++++-
src/gateway/role-policy.ts | 18 ++++++++++++++++--
src/gateway/server/ws-connection/connect-policy.ts | 9 ++++++++-
```
Audit context
I audited the codebase for every place the no-auth flag should reach. Findings:
So this closes the active set. #5 may need follow-up if HTTP-tool flows surface similar issues, but there's no known regression there yet.
Test plan