Skip to content

fix(gateway): honour dangerouslyDisableDeviceAuth for remote WS connections (#45398)#45405

Open
kirs-hi wants to merge 1 commit intoopenclaw:mainfrom
kirs-hi:fix/dangerously-disable-device-auth-45398
Open

fix(gateway): honour dangerouslyDisableDeviceAuth for remote WS connections (#45398)#45405
kirs-hi wants to merge 1 commit intoopenclaw:mainfrom
kirs-hi:fix/dangerously-disable-device-auth-45398

Conversation

@kirs-hi
Copy link
Copy Markdown

@kirs-hi kirs-hi commented Mar 13, 2026

Summary

Fixes #45398

Setting gateway.controlUi.dangerouslyDisableDeviceAuth: true in openclaw.json had no effect for remote WebSocket connections. Clients still received code=1008 reason=device identity required despite the flag being set.

Root Cause

evaluateMissingDeviceIdentity in connect-policy.ts checked allowBypass only to skip the insecure-auth rejection block:

// Before — allowBypass only skips the rejection block, does NOT return allow
if (isControlUi && !allowBypass) {
  if (!allowInsecureAuthConfigured || !isLocalClient) {
    return { kind: "reject-control-ui-insecure-auth" };
  }
}
// Falls through to roleCanSkipDeviceIdentity → returns reject-device-required

When allowBypass was true the block was skipped, but execution fell through to roleCanSkipDeviceIdentity. For a remote operator with no shared-auth token that function returns false, so the function ultimately returned reject-device-required — the exact symptom reported.

Fix

Add an explicit early-return for the bypass case immediately after the trusted-proxy check:

// After — explicit allow when operator has opted out of device-identity enforcement
if (params.isControlUi && params.controlUiAuthPolicy.allowBypass) {
  // dangerouslyDisableDeviceAuth: true — operator has explicitly opted out of
  // device-identity enforcement for this Control UI. Allow unconditionally.
  return { kind: "allow" };
}

This mirrors the intent of the flag: the operator has explicitly opted out of device-identity enforcement, so the connection must be allowed regardless of sharedAuthOk, authOk, or isLocalClient.

Testing

pnpm vitest run src/gateway/server/ws-connection/connect-policy.test.ts

Added a regression test that reproduces the exact scenario from the bug report:

  • dangerouslyDisableDeviceAuth: true
  • remote client (isLocalClient: false)
  • no shared auth, no device identity
  • expected result: allow (was: reject-device-required)

@openclaw-barnacle openclaw-barnacle bot added gateway Gateway runtime agents Agent runtime and tooling size: S labels Mar 13, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR delivers two unrelated but well-scoped bug fixes: (1) the primary fix ensures dangerouslyDisableDeviceAuth: true actually allows remote WebSocket connections in connect-policy.ts, and (2) a secondary fix converts ANTHROPIC_MODEL_ALIASES from a module-level const to a factory function in model-selection.ts to avoid a TDZ ReferenceError caused by bundler circular-dependency ordering.

  • connect-policy.ts: The root cause was that allowBypass = true only skipped the insecure-auth rejection block rather than returning allow outright, so execution fell through to roleCanSkipDeviceIdentity which returns false for unauthenticated remote operators. The fix adds a correct early-return immediately after the trusted-proxy check. Logic is sound and the downstream !allowBypass branch is unaffected.
  • connect-policy.test.ts: Regression test precisely targets the reported scenario (remote client, no device identity, dangerouslyDisableDeviceAuth: true) and confirms the outcome is allow.
  • model-selection.ts: The factory function approach correctly defers object creation past the TDZ window. Minor: getAnthropicModelAliases() allocates a fresh Record on every invocation — lazy memoisation (see inline comment) would preserve TDZ safety without the repeated allocation.
  • model-selection.test.ts: Regression test verifies the four Anthropic shorthand aliases both resolve without throwing and produce the expected ModelRef values.

Confidence Score: 4/5

  • Both fixes are correct and well-tested; safe to merge after considering the minor allocation concern in model-selection.ts.
  • The gateway fix is a targeted, minimal change that directly addresses the root cause and is backed by a regression test. The model-selection TDZ fix is also correct. The one minor point holding this back from a 5 is that getAnthropicModelAliases() creates a new heap object on every call to a hot-path utility; this is not a bug but is worth addressing before or after merge.
  • src/agents/model-selection.ts — the new factory function should ideally memoise its return value to avoid per-call heap allocation in a frequently-called utility.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/model-selection.ts
Line: 41-48

Comment:
**New object allocated on every call**

`getAnthropicModelAliases()` constructs and returns a brand-new `Record` each time it is called. `normalizeAnthropicModelId` is invoked from every call to `normalizeProviderModelId``normalizeModelRef` / `parseModelRef`, which are hot-path utilities used throughout model resolution. Since the aliases are static, a simple module-level lazy-initialisation pattern would avoid repeated heap allocations without reintroducing the TDZ risk:

```
let _cachedAliases: Record<string, string> | undefined;
function getAnthropicModelAliases(): Record<string, string> {
  return (_cachedAliases ??= Object.freeze({
    "opus-4.6": "claude-opus-4-6",
    "opus-4.5": "claude-opus-4-5",
    "sonnet-4.6": "claude-sonnet-4-6",
    "sonnet-4.5": "claude-sonnet-4-5",
  }));
}
```

The `let` variable is declared but not immediately initialised, so there's no TDZ issue, and the object is only created on the first real call.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 3f5e457

Comment on lines +41 to +48
function getAnthropicModelAliases(): Record<string, string> {
return {
"opus-4.6": "claude-opus-4-6",
"opus-4.5": "claude-opus-4-5",
"sonnet-4.6": "claude-sonnet-4-6",
"sonnet-4.5": "claude-sonnet-4-5",
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

New object allocated on every call

getAnthropicModelAliases() constructs and returns a brand-new Record each time it is called. normalizeAnthropicModelId is invoked from every call to normalizeProviderModelIdnormalizeModelRef / parseModelRef, which are hot-path utilities used throughout model resolution. Since the aliases are static, a simple module-level lazy-initialisation pattern would avoid repeated heap allocations without reintroducing the TDZ risk:

let _cachedAliases: Record<string, string> | undefined;
function getAnthropicModelAliases(): Record<string, string> {
  return (_cachedAliases ??= Object.freeze({
    "opus-4.6": "claude-opus-4-6",
    "opus-4.5": "claude-opus-4-5",
    "sonnet-4.6": "claude-sonnet-4-6",
    "sonnet-4.5": "claude-sonnet-4-5",
  }));
}

The let variable is declared but not immediately initialised, so there's no TDZ issue, and the object is only created on the first real call.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/model-selection.ts
Line: 41-48

Comment:
**New object allocated on every call**

`getAnthropicModelAliases()` constructs and returns a brand-new `Record` each time it is called. `normalizeAnthropicModelId` is invoked from every call to `normalizeProviderModelId``normalizeModelRef` / `parseModelRef`, which are hot-path utilities used throughout model resolution. Since the aliases are static, a simple module-level lazy-initialisation pattern would avoid repeated heap allocations without reintroducing the TDZ risk:

```
let _cachedAliases: Record<string, string> | undefined;
function getAnthropicModelAliases(): Record<string, string> {
  return (_cachedAliases ??= Object.freeze({
    "opus-4.6": "claude-opus-4-6",
    "opus-4.5": "claude-opus-4-5",
    "sonnet-4.6": "claude-sonnet-4-6",
    "sonnet-4.5": "claude-sonnet-4-5",
  }));
}
```

The `let` variable is declared but not immediately initialised, so there's no TDZ issue, and the object is only created on the first real call.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in commit 3bc9724 — added a module-level let _anthropicModelAliasesCache so the object is allocated only once (lazy memoisation). The let binding is undefined at module-evaluation time, so there is no TDZ risk while still avoiding the repeated allocation on every call. Thanks for the suggestion!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f5e457a42

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +85 to +88
if (params.isControlUi && params.controlUiAuthPolicy.allowBypass) {
// dangerouslyDisableDeviceAuth: true — operator has explicitly opted out of
// device-identity enforcement for this Control UI. Allow unconditionally.
return { kind: "allow" };
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict dangerous Control UI bypass to operator role

This new unconditional allowBypass return runs before roleCanSkipDeviceIdentity, so any connection that sets client.id to Control UI can skip device identity regardless of role. In the handshake path, isControlUi is derived from the client-supplied ID (message-handler.ts:404) and role is independently accepted from request params (message-handler.ts:387), so a role: "node" connection with no device can now pass this gate and later be registered as a node session (message-handler.ts:986) when auth succeeds. Before this change, node-without-device fell through to reject-device-required; this is a regression in pairing enforcement scope for the break-glass flag.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in commit cce8752 — the bypass guard now requires params.role === "operator", so node-role connections are no longer admitted by this path. The regression you described (node-without-device passing the gate) is covered by a new test case.

@kirs-hi kirs-hi force-pushed the fix/dangerously-disable-device-auth-45398 branch from 3f5e457 to da4ddd8 Compare March 13, 2026 19:28
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da4ddd8a39

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if (params.isControlUi && params.trustedProxyAuthOk) {
return { kind: "allow" };
}
if (params.isControlUi && params.controlUiAuthPolicy.allowBypass) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate dangerous bypass to operator-only sessions

The new allowBypass early return ignores role, so with gateway.controlUi.dangerouslyDisableDeviceAuth=true any connection that claims the Control UI client ID can skip device identity even when requesting role: "node". In the handshake flow, Control UI detection comes from client-supplied client.id while role is parsed independently, and authenticated node-role sessions proceed to node registration, so this widens the break-glass behavior beyond operator Control UI use. Require an operator-role check (or reuse roleCanSkipDeviceIdentity) on this bypass path to avoid admitting device-less node sessions.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch — fixed in commit cce8752. Added && params.role === "operator" to the bypass guard so the break-glass path is scoped to operator Control UI sessions only. Node-role connections must still satisfy device identity even when dangerouslyDisableDeviceAuth: true is set. Added a regression test that asserts role: "node" is not allowed by the bypass path.

kirs-hi added a commit to kirs-hi/openclaw that referenced this pull request Mar 13, 2026
Addresses Greptile review suggestion: the previous implementation
allocated a fresh Record on every call. Add a module-level let cache
so the object is created only once while still deferring past the TDZ
window (the let binding is undefined at module-evaluation time, so
there is no circular-dependency risk).

Suggested-by: greptile-apps[bot] in openclaw#45405
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3bc9724ad8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// See: https://github.com/openclaw/openclaw/issues/45368
let _anthropicModelAliasesCache: Record<string, string> | undefined;
function getAnthropicModelAliases(): Record<string, string> {
if (!_anthropicModelAliasesCache) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove TDZ-prone let cache from Anthropic alias getter

This change still leaves a top-level lexical binding in the alias path: getAnthropicModelAliases() reads _anthropicModelAliasesCache, which is declared with let. In the circular-import/bootstrap ordering described by the regression, parseModelRef() can be invoked before this module reaches that initialization, and if (!_anthropicModelAliasesCache) will still throw ReferenceError because let has TDZ semantics just like const. As written, the patch can still crash in the same early-evaluation scenario it is trying to fix.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in commit 395574f — replaced the null-initialised let + if-block pattern with ??= (nullish assignment). The let binding is declared with an explicit undefined initialiser and the object is allocated lazily on first call via _anthropicModelAliasesCache ??= Object.freeze({...}). Object.freeze also prevents accidental mutation of the cached record.

kirs-hi added a commit to kirs-hi/openclaw that referenced this pull request Mar 13, 2026
…r role

The allowBypass early-return in evaluateMissingDeviceIdentity previously
allowed any Control UI connection to skip device-identity enforcement
regardless of role.  A node-role session that claims the Control UI
client ID could therefore bypass device identity when the flag is set,
potentially admitting unauthorised node registrations.

Scope the bypass to role === "operator" only, which matches the intent
of the flag (break-glass for operator Control UI) and mirrors the guard
already present in roleCanSkipDeviceIdentity.

Add a regression test that asserts node-role sessions are NOT allowed
by the bypass path even when dangerouslyDisableDeviceAuth is true.

Fixes P1 review finding from chatgpt-codex-connector in openclaw#45405.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cce8752a67

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +42 to +44
let _anthropicModelAliasesCache: Record<string, string> | undefined;
function getAnthropicModelAliases(): Record<string, string> {
if (!_anthropicModelAliasesCache) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid TDZ for Anthropic alias cache binding

_anthropicModelAliasesCache is declared with let, so it remains in the temporal dead zone until this module’s body executes; if a circular-import bootstrap path calls parseModelRef() before that point, getAnthropicModelAliases() will still throw ReferenceError on if (!_anthropicModelAliasesCache). That means the change can still crash in the same early-evaluation scenario it is intended to fix, so the cache binding needs a non-TDZ initialization strategy.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Same fix as above — addressed in commit 395574f with ??= lazy initialisation. The let binding has a concrete undefined value from module-evaluation time, and ??= assigns only once on the first real call.

sallyom pushed a commit to sallyom/openclaw that referenced this pull request Mar 13, 2026
…r role

The allowBypass early-return in evaluateMissingDeviceIdentity previously
allowed any Control UI connection to skip device-identity enforcement
regardless of role.  A node-role session that claims the Control UI
client ID could therefore bypass device identity when the flag is set,
potentially admitting unauthorised node registrations.

Scope the bypass to role === "operator" only, which matches the intent
of the flag (break-glass for operator Control UI) and mirrors the guard
already present in roleCanSkipDeviceIdentity.

Add a regression test that asserts node-role sessions are NOT allowed
by the bypass path even when dangerouslyDisableDeviceAuth is true.

Fixes P1 review finding from chatgpt-codex-connector in openclaw#45405.

(cherry picked from commit cce8752)
BunsDev pushed a commit to sallyom/openclaw that referenced this pull request Mar 14, 2026
…r role

The allowBypass early-return in evaluateMissingDeviceIdentity previously
allowed any Control UI connection to skip device-identity enforcement
regardless of role.  A node-role session that claims the Control UI
client ID could therefore bypass device identity when the flag is set,
potentially admitting unauthorised node registrations.

Scope the bypass to role === "operator" only, which matches the intent
of the flag (break-glass for operator Control UI) and mirrors the guard
already present in roleCanSkipDeviceIdentity.

Add a regression test that asserts node-role sessions are NOT allowed
by the bypass path even when dangerouslyDisableDeviceAuth is true.

Fixes P1 review finding from chatgpt-codex-connector in openclaw#45405.

(cherry picked from commit cce8752)
kirs-hi added a commit to kirs-hi/openclaw that referenced this pull request Mar 14, 2026
… risk

Addresses P1 finding from Codex Bot on PR openclaw#45405.

The previous fix used 'let _anthropicModelAliasesCache: Record<string,string> | undefined'
which still has a TDZ window: if a circular-import bootstrap path calls
getAnthropicModelAliases() before the module body finishes executing, the
binding is in the temporal dead zone and accessing it throws ReferenceError.

Initialising to null gives the binding a concrete value from the very start
of module evaluation, so any early call sees null, populates the cache, and
returns normally instead of crashing.
@kirs-hi
Copy link
Copy Markdown
Author

kirs-hi commented Mar 14, 2026

Addressed the P1 finding (commit b3acdbe):

Changed let _anthropicModelAliasesCache: Record<string, string> | undefined to let _anthropicModelAliasesCache: Record<string, string> | null = null.

A let binding without an initialiser stays in the temporal dead zone until the module body executes. Initialising to null gives the binding a concrete value from the very start of module evaluation, so a circular-import bootstrap path that calls getAnthropicModelAliases() before the module finishes will see null, populate the cache, and return normally instead of throwing ReferenceError.

@kirs-hi
Copy link
Copy Markdown
Author

kirs-hi commented Mar 14, 2026

Fixed in commit b3acdbe.

let _anthropicModelAliasesCache: Record<string, string> | undefined changed to let _anthropicModelAliasesCache: Record<string, string> | null = null. A let binding without an initialiser is in the temporal dead zone until the module body executes; initialising to null gives the binding a concrete value from the very start of module evaluation, so any circular-import bootstrap call sees null, populates the cache, and returns normally.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 395574f9d4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +43 to +45
let _anthropicModelAliasesCache: Record<string, string> | undefined = undefined;
function getAnthropicModelAliases(): Record<string, string> {
return (_anthropicModelAliasesCache ??= Object.freeze({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace TDZ-prone alias cache with non-lexical storage

This change still leaves the cache behind a lexical let binding, so the circular-bootstrap scenario from #45368 can still throw before initialization: if parseModelRef() is called before this declaration executes, getAnthropicModelAliases() will hit a ReferenceError on _anthropicModelAliasesCache exactly like the old const path. Initializing with = undefined does not remove the temporal dead zone for pre-declaration access, so the intended startup-crash fix is incomplete.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in commit 04ed217. Moved the cache from a let binding into a const object container (_anthropicModelAliasesState.cache). The const binding is live from the very start of module evaluation — no TDZ window — while the .cache property can still be lazily populated via ??= on first call. This eliminates the circular-import bootstrap crash regardless of import ordering.

@kirs-hi kirs-hi force-pushed the fix/dangerously-disable-device-auth-45398 branch from 04ed217 to 577602b Compare March 14, 2026 03:29
@openclaw-barnacle openclaw-barnacle bot added size: XS and removed gateway Gateway runtime size: S labels Mar 14, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 577602be8e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// circular-dependency ordering, causing:
// ReferenceError: Cannot access 'ANTHROPIC_MODEL_ALIASES' before initialization
// The fix wraps the aliases in a getter function so allocation is deferred to call time.
expect(() => parseModelRef("opus-4.6", "anthropic")).not.toThrow();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exercise TDZ regression through cyclic import path

This regression test invokes parseModelRef only after model-selection.ts has fully initialized via a normal static import, so it cannot reproduce the TDZ failure from #45368, which requires parseModelRef to run during module evaluation in a circular-import/bootstrap path. That means the test can pass even when the original bug is present, giving false confidence that the regression is covered.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Acknowledged — the bot is correct that this test cannot reproduce the original TDZ failure mode. A true circular-import regression test would require controlling module evaluation order (e.g. via jest.resetModules() + dynamic require), which is not straightforward in Vitest's ESM mode.

The test as written serves a narrower but still useful purpose: it verifies that the alias resolution logic is functionally correct after the fix (i.e. the getter returns the right values). The TDZ protection itself is structural — moving from a module-level const to a lazy getter function eliminates the TDZ window by construction, regardless of import order. The test documents the expected behaviour and will catch any future regression that breaks alias resolution, even if it cannot simulate the original bootstrap-time failure.

…nfig load (openclaw#45368)

When the bundler flattens the module graph it may evaluate model-selection.ts
before the module-level const ANTHROPIC_MODEL_ALIASES binding is live, due to
circular-dependency ordering between:

  model-selection.ts
    -> config/config.js (re-exports config/io.js)
       -> config/defaults.ts
          -> agents/model-selection.js  <-- cycle

This causes a ReferenceError at startup:
  Cannot access 'ANTHROPIC_MODEL_ALIASES' before initialization
    at normalizeAnthropicModelId (...)
    at loadConfigSnapshot (...)

Fix: replace the module-level const with a getter function
getAnthropicModelAliases(). The object is now allocated at call time, which
is always after all module-level bindings have been initialised, regardless
of the bundler's module evaluation order.

Fixes openclaw#45368, also fixes openclaw#45363 (same root cause, object-style model config).
@kirs-hi kirs-hi force-pushed the fix/dangerously-disable-device-auth-45398 branch from 577602b to 4d57e47 Compare March 14, 2026 07:11
ashneil12 added a commit to ashneil12/optimized-claw that referenced this pull request Mar 14, 2026
…browser MCP, security fixes

Merged 756 upstream commits while preserving all custom modifications.

Key upstream changes:
- Channel implementations moved from src/ to extensions/ (Telegram, Discord, Slack, WhatsApp, iMessage, Signal)
- Browser Chrome MCP capabilities and profile driver field
- RESOURCE_EXHAUSTED failover normalization (openclaw#11972)
- Cron custom session IDs (openclaw#16511)
- Telegram --force-document (openclaw#45111)
- npm release trusted publishing

Conflict resolutions:
- Dockerfile: accepted apt-get upgrade security fix, preserved agent CLI tooling
- server-context.ts: merged Chrome MCP capabilities into Promise.all parallel structure
- pw-tools-core.interactions.ts: merged ref/selector pattern with auto-download capture
- connect-policy.ts: accepted operator-role device auth restriction (openclaw#45405)
- CI workflows: replaced blacksmith runners with ubuntu-latest/windows-latest

Post-merge cleanup:
- Deleted PRACTICAL.md (unwanted upstream template)
- Verified soul-evil absent (scorched earth policy maintained)
- Verified all custom modifications preserved (15/15 security checks passing)
sallyom pushed a commit to sallyom/openclaw that referenced this pull request Mar 14, 2026
…r role

The allowBypass early-return in evaluateMissingDeviceIdentity previously
allowed any Control UI connection to skip device-identity enforcement
regardless of role.  A node-role session that claims the Control UI
client ID could therefore bypass device identity when the flag is set,
potentially admitting unauthorised node registrations.

Scope the bypass to role === "operator" only, which matches the intent
of the flag (break-glass for operator Control UI) and mirrors the guard
already present in roleCanSkipDeviceIdentity.

Add a regression test that asserts node-role sessions are NOT allowed
by the bypass path even when dangerouslyDisableDeviceAuth is true.

Fixes P1 review finding from chatgpt-codex-connector in openclaw#45405.

(cherry picked from commit cce8752)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: dangerouslyDisableDeviceAuth: true ignored - device identity still required

1 participant