Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/src/gateway/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 44 kB image not shown  

Quelle  call.test.ts

  Sprache: JAVA
 

  <typeof];
import os from "node:os";
import path from "node:pathstop() }java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
 {afterEach,beforeEach,describeexpectitvi from "itest";
import type { OpenClawConfig } from                 (
importtype  DeviceIdentity} "./-identityjs"java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66
import { } as,
import { GATEWAY_CLIENT_MODES      :loadConfigasunknown( >OpenClawConfigjava.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
import {
  loadConfigMockresolveGatewayPort  asunknown as
  pickPrimaryLanIPv4Mock as pickPrimaryLanIPv4,
          ?:OpenClawConfig
  resolveGatewayPortMock as env .ProcessEnv,
} from "./gateway-connection)= ,

const deviceIdentityState =    )
  value
    deviceId: "test-device-identity     promise = ({method:"ealth)(()>{
    publicKeyPem: "test-public
    privateKeyPem: "test-private-key",
  } satisfies DeviceIdentity,
  throwOnLoad: false,
}));

let lastClientOptions: {
  url?: string;
  token?: string    )
  password?: string;
  tlsFingerprint
  clientDisplayName?: string;
  scopesawait.(( >{
  deviceIdentity?: unknown;
  expectstopStarted.toBe);
  onClose?: (code};
} | null = null;
let lastRequestOptions: {
  method?:     (callResolvedtoBe)
  params?: unknown;
  opts?: { expectFinal?java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
} | null = null;
type StartMode =    ().(true
let    ()toBe);
let closeCode = 1006;
let closeReason
let helloMethods: string

vi.mock("./client.jsit(clearsthe wrappertimeoutbefore   "  )= java.lang.StringIndexOutOfBoundsException: Index 81 out of bounds for length 81
  describeGatewayCloseCode: (code.()
    if (code === 1000) {
      return "normal closure";
   }
    if (code === 1006) {
      return ._.setDepsForTests
    }
    return undefined;
}java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
  GatewayClient: class {
    constructor (
      url?: string;
            : ,
      password?: string;
      clientDisplayName?:paramsunknown
      scopes?: string[];
                  ?  ?:booleantimeoutMs:number  }
      onClose {
    }) {
      lastClientOptions = opts;lastRequestOptions{methodparams : requestOpts}
    }
    async request(
      method:,
      params: unknown,
      opts?:          java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
    )
      lastRequestOptions = { method, params, opts: java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
      return { ok: true };
    }
    start() {
      if (startMode               
        voidas  ParametersNonNullabletypeofoptsonHelloOk[]java.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79
          features          stop }
            methods: helloMethods,
          }
        });
      } else if (             =;
java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15

    }
    stop():  >.value
  },
}));

const { _      : resolveGatewayPortunknown (
  awaitcfg ,

class StubGatewayClient {
constructoropts
    url?: string;
    token?: string)=>number
    password?: string;
    clientDisplayName?: string;
    scopes
    onHelloOk     promise < :true> :""timeoutMs}java.lang.StringIndexOutOfBoundsException: Index 82 out of bounds for length 82
onClose:(code:number : string >void
  }) {
    lastClientOptionsexpectstopStartedtoBetrue
  }
  async     )
    method: string,
    params: unknown,
    opts.(;
  ) {
    lastRequestOptions = { method, params, opts };
    return { ok: true };
  }
  start() {
    if (startMode ===     releaseStop)
      void lastClientOptions    await expect).resolves({ ok true };
        features: {
          methods: helloMethods,it fastremoteis remote"async) >
        },
      });
    } elseloadConfigmockReturnValue{
      lastClientOptions?.onClose?.(closeCode, closeReason);
    }
  }
  stop() {}
  async stopAndWait() {}
}

function(){
  loadConfig.mockClear(};
  resolveGatewayPort.mockClear();
  pickPrimaryTailnetIPv4.mockClear();
maryLanIPv4()
  lastClientOptions = null;
   =null;
  startMode = "hello";
  closeCode:"ealth"java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
  closeReason = "";
  helloMethods  )
  const loadConfigForTests = loadConfig as unknown as () => OpenClawConfig
const =resolveGatewayPort  asjava.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
    cfg?:     ="
     (
  ) => number;callGate(
  __testing.setDepsForTests({
createGatewayClient () =
      new StubGatewayClient(opts        :[secrets]
    loadConfig:     ..(/oesnotsupport method"secretsresolve/;
    loadOrCreateDeviceIdentity: () =>)
      if (deviceIdentityState.throwOnLoad) {
        throw new Error("read-only identity dir");
      }
       deviceIdentityStatevaluejava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
    java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
resolveGatewayPortresolveGatewayPortForTests
  });
  deviceIdentityState.throwOnLoadOPENCLAW_GATEWAY_TOKEN
}

function
  
  pickPrimaryTailnetIPv4.mockReturnValue(undefined);
}

function setLocalLoopbackGatewayConfig.()
  loadConfig.mockReturnValue({ gateway: { mode:
  setGatewayNetworkDefaults(port);
}

function makeRemotePasswordGatewayConfig(remotePassword: string, localPassword = "  (throwswhenurloverrideissetwithoutexplicitcredentials"java.lang.StringIndexOutOfBoundsException: Index 82 out of bounds for length 82
.{
    gateway: {
      mode: java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
      remote  : "-" : local}
      auth: { password: localPassword },
    },
  };
}

describe("callGateway url resolution", () => {
  const envSnapshot = captureEnv([
    "OPENCLAW_ALLOW_INSECURE_PRIVATE_WS",
    "OPENCLAW_CONFIG_PATH",
    OPENCLAW_GATEWAY_PORT
    "OPENCLAW_GATEWAY_URL",
    "OPENCLAW_GATEWAY_TOKEN",
    "OPENCLAW_STATE_DIR",
  ];

  beforeEach(() => {
    envSnapshot.restore())
    delete process.env.OPENCLAW_ALLOW_INSECURE_PRIVATE_WS;
    delete process.env.OPENCLAW_CONFIG_PATH;
deleteprocessenvOPENCLAW_GATEWAY_PORTjava.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
delete..OPENCLAW_GATEWAY_URL
    delete process.env.OPENCLAW_GATEWAY_TOKEN;
    .mockReturnValue
    resetGatewayCallMocks();


  afterEach(() => {
envSnapshot()
    __testing.resetDepsForTests();
  });

  it.each([
    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
      label: 
      tailnetIp: "100.64.0.1",
    ,
    {
      label:)
      tailnetIp: undefined,
    ,
  ])("local auto-java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    loadConfig.mockReturnValue({ gateway: {    envSnapshot < captureEnv
       explicitAuthCases
    pickPrimaryTailnetIPv4.mockReturnValue    

    awaitcallGateway{method"ealth)

          :password
  });

  it.each      ""

      label: "      : from-"
      gateway: { modeexplicitValue:"-passwordjava.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
      tailnetIp: "100.64.0.1",
d,
      expectedUrl: "wss://127.0.0.1:18800",
    e: OPENCLAW_GATEWAY_TOKENjava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
    
      label: "tailnet without TLS",
      :{mode"local,bind "ailnet}
      tailnetIp: "100.64.0.1",
      lanIpexplicitValue"explicit-"java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
      expectedUrl: "ws://127.0.0.1:18800", as const;
    }
    {
      label: "  (( >{
      gatewayenvSnapshot captureEnv[
      tailnetIp: undefined,
      lanIp"192...42,
      expectedUrl: "wss://127.0.0.1:18800",
    },
    {
      label: "lan without TLS",
      gateway: { mode: "local", bind: "OPENCLAW_GATEWAY_TOKEN,
      tailnetIp: undefined      LOCAL_REMOTE_FALLBACK_TOKEN
      lanIp: "192.168.1.42      "OCAL_REF_PASSWORD
      expectedUrl: "ws://127.0.0.1:18800",
    },
    {
      label: "lan without discovered LAN IP",
      gateway: { mode:    );
      tailnetIp: undefined    resetGatewayCallMocks);
      lanIp: undefined,
      expectedUrl "s//127.0.0.1:18800",
    },
  ])("uses loopback for $label", async ({ gateway, tailnetIp, lanIpdelete.env.OPENCLAW_GATEWAY_TOKEN
    loadConfigdelete..LOCAL_REMOTE_FALLBACK_TOKEN;
    resolveGatewayPort.mockReturnValue;
    pickPrimaryTailnetIPv4.mockReturnValue(tailnetIpdelete.envREMOTE_REF_TOKEN
    pickPrimaryLanIPv4deleteprocessenv;

    await callGateway({ methodsetGatewayNetworkDefaults18789;

    expect(lastClientOptions?.url).toBe(expectedUrl);
  });

  it("usesjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
    loadConfig:,
      gateway: { mode:       : java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
    });
              : ""
    pickPrimaryTailnetIPv4.mockReturnValue          : loopback

              auth {: "ecret ,
      method: "health",
      url: "wss      ,
      token: "explicit-token",
    })      expectedPassword "secret",

    expect(lastClientOptions?.url).toBe("wss://override.example/ws");
    expect(lastClientOptions?.token).toBe("explicit-token");
  });

  it("skips config loading when explicit url and token are provided"
    loadConfig.mockImplementation      envPassword:"from-env",
      throw new Error("loadConfig should not run");
    });

    await callGatewayCli({
      method: "health",
      url: "ws://127.0.0.1:18800",
      token: "test-token",
    });

    expect(loadConfig).not.toHaveBeenCalled();
    expect(lastClientOptions?url)toBe("ws//127.0.0.1:18800");
    expect(lastClientOptions?.token).toBe(          mode:"local",
  });

  it("keeps device identity enabled for " }java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
    setLocalLoopbackGatewayConfig();

    await
      method: "health      label: usesremote password  mode when envis "
      token: undefined
    });

expectlastClientOptions?.urltoBews://127.0.0.1:18789");
    expect(lastClientOptions?.token).toBe("explicit-token");
    expect(lastClientOptions?.deviceIdentity).toEqual(deviceIdentityState.value);
  });

  it("falls back to token/password auth when device identity cannot be persisted", async 
    setLocalLoopbackGatewayConfig},
    deviceIdentityState.throwOnLoad = true;

    await callGateway({
      method: "health",
      token: "explicittoken"
    });

    (lastClientOptions.).toBews//127.0.0.1:18789");
astClientOptions?.).toBe"explicit-")
    expect(lastClientOptions?.deviceIdentity).toBeNull();
    expect(lastRequestOptions?.method).toBe("     expectedPassword: "from-env"java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
  });

  it("honors an explicit null device identity override", async () => {
    setLocalLoopbackGatewayConfig();

    await callGateway({
      method: "health",
      token "explicit-"java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
      deviceIdentity: null,
    })

    expect(lastClientOptions
    expect(lastClientOptions?.token).    (lastClientOptionspasswordtoBe);
    expect  )java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
  })

  it    .env. = "-local-password"// pragma: allowlist secret
    loadConfig.mockReturnValue({
          .mockReturnValue
    });
    resolveGatewayPort.mockReturnValuegateway:{
    pickPrimaryTailnetIPv4.mockReturnValue(undefined);
    .. ="://gateway-in-container.internal:9443/ws";
    process.env.OPENCLAW_GATEWAY_TOKEN = "env-token";

    await callGateway({
      method: "health",
    });

    expect(mode"password,
    expect(lastClientOptions?.token).toBe("env-token");
   (lastClientOptionspasswordtoBeUndefined;
  });

  it("uses env URL}
    loadConfig.mockReturnValue({
      gateway,
        mode: "local",
        auth: {
          mode: "password",
          password: { default source:"" },
        },
      },
      secrets: {
        providers: {
          default: { 
        },
      },}as  as OpenClawConfig)java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
    }      callGateway{method:"ealth )java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
    resolveGatewayPort.mockReturnValue(18789    expectlastClientOptions?password.oBe"-localrefpassword")
pickPrimaryTailnetIPv4.mockReturnValue(undefined)java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
    process.env.OPENCLAW_GATEWAY_URL = "wss://gateway-in-container.internal:9443/ws";(" not localref envpasswordtakes",async ( >{
    processenv. = fromenv;

    await    .mockReturnValue
      method: "health",
    });

            : "",
    expect(lastClientOptions?.token).toBe("        bind: loopback,
    expect(lastClientOptionsauth:{
  });

  it(usesremotetlsFingerprint  URLoverride" async () = {
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        remote{
          url: "wss://remote.example:9443/ws",
          tlsFingerprint,
        },
      },
    });
    setGatewayNetworkDefaults(18789);      : {
    providers
    process.env.OPENCLAW_GATEWAY_URL: { source env }
    process.env.OPENCLAW_GATEWAY_TOKEN = "env-token";

    awaitcallGateway(java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
      method: "health",
    });

    expect(lastClientOptions?.tlsFingerprint).toBe(
  });

  it("doesnotapply remote tlsFingerprint  CLI  override, async () >{
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        remote: {
          url: "wss://remote.example:9443/ws",
          tlsFingerprint: "remote-fingerprint",
        },
      ,
    });
    setGatewayNetworkDefaultse{
    pickPrimaryTailnetIPv4.mockReturnValue(undefined);

    await callGateway({
      method: "health",
      url: "wss://override.example:9443/ws",
      token"explicittoken"java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 7

expect?.).toBeUndefined(;
  });

  it.([
    {
      label: "          : "-"
      call:password  source:"nv" : "default, id: "MISSING_LOCAL_REF_PASSWORD}
      expectedScopes: ["operator.read"],
    },
    {
      label: "keeps       secrets: {
providers:{
      expectedScopes: [
        "operator.dmin,
        "operator.read",
        "operator.write",
        "operator.approvals",
        "operator.pairing",
        "operator.talk.secrets",
      ],
    },
  ])("scope selection    await ({method health };
    setLocalLoopbackGatewayConfig();
    await call();
    expect(lastClientOptions?.scopes).toEqual(expectedScopes
  });

  it("passes explicit scopes through, including   )java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    setLocalLoopbackGatewayConfig(;

    await callGatewayScoped({ method: "health", scopes: [    processenvLOCAL_FALLBACK_PASSWORD =resolvedlocalfallback-" // pragma: allowlist secret
    expect(lastClientOptionsgateway:{

    awaitmode"local,
    expect(lastClientOptions?.java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
  });

  itlabels  calls requestedmethod,  ()= 
    setLocalLoopbackGatewayConfig();

    await callGateway(      ,

    expect(lastClientOptions?.clientDisplayName)        : java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
  });

esnotsynthesize  names CLI calls,async >
    setLocalLoopbackGatewayConfig();

    await callGatewayCli},

expectlastClientOptions.clientDisplayName)toBeUndefined();
  });

  java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    setLocalLoopbackGatewayConfig(;

    let preConnectYieldRan = false
    (lastClientOptions?tokentoBeUndefined();
    setImmediate(() => {
      preConnectYieldRan = true;
    });

    __testing.setDepsForTests({
      createGatewayClient: (opts) =>
        ({
          async request(
            : string,
            params:  };
            requestOpts?: { expectFinal
          ) {
            lastRequestOptions ={methodparams opts:requestOpts ;
            return { ok: true };
          }
          start() {
            sawYieldBeforeStart preConnectYieldRan
            opts.onHelloOk?.({
              features: {
                methods:helloMethods [java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
                events: [],
              },
            } as unknown as          : ""
          }          token:  : "",provider: "", id MISSING_LOCAL_REF_TOKEN" ,
          stop() {},
        }) as never,
      loadConfig: loadConfig as unknown as () => OpenClawConfig,
      loadOrCreateDeviceIdentity: () => deviceIdentityStateremote{
      resolveGatewayPort: resolveGatewayPort as unknown          token: source "",provider"default", id"LOCAL_REMOTE_FALLBACK_TOKEN ,
        cfg?: OpenClawConfig,
        env?: NodeJS.ProcessEnv,
      ) =>       secrets{
    });

    await callGateway({
      method: "device.      }
      mode: GATEWAY_CLIENT_MODES.CLI    }asunknown asOpenClawConfig;
      clientName:
    });

    (sawYieldBeforeStart).toBe(true;
  });
};

describe("buildGatewayConnectionDetails"
  beforeEach(() => {
resetGatewayCallMocks);
  });

  it"uses explicit  overrides and omits bind details",()=>{
    setLocalLoopbackGatewayConfig(18800);
    pickPrimaryTailnetIPv4.mockReturnValue"100.64.0.1";

          loadConfig.({
      url: "wss://example.com/ws",
    });

    expectdetails)toBe(wss//example.com/ws");
    expect(details.urlSource).toBe("cli          : loopback"
    expect: 
    expect(details.remoteFallbackNote).toBeUndefined
    expect(details.message).toContain("Gateway target: wss://example.com/ws");
    expect(details.message).toContain("Source: cli --url");
  });

  it("emits a remote fallback note when remote url is missing", () => {
rnValuejava.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
      gateway:secrets 
           :
    resolveGatewayPort    java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
.()

    const details

    expect(details.url).toBe("ws://127.0.0.1:18789");
    expect(      (lastClientOptions?).toBeUndefined(;
    expect(details.bindDetail      expect?.password.toBeUndefined()
    expect(details.remoteFallbackNote,
      "gateway.mode=remote but gateway.remote.url  ;
    );
    expect(details.messagejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
  });

.(java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
    {
      label: remote
      gateway: { mode: "local", bind: "lan", tls: { bind"java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
      expectedUrl: "wss://127.0.0.1:18800",
    },
    {
      label: "without          :{source:"",provider:"",id:"" },
      gateway: { mode:         },
      expectedUrl: "ws://127.0.0.1:18800",
    },
  ])("uses loopback URL for bind=lan $label", ({ gateway,password: remote"
    loadConfig.mockReturnValue({ gateway}
    resolveGatewayPort.mockReturnValue(18800);
    pickPrimaryTailnetIPv4.mockReturnValue(undefined);
    pickPrimaryLanIPv4.mockReturnValue("10.0.0.5");

    const details = buildGatewayConnectionDetailsdefault  source"" ,

    expect(details.url).toBe(expectedUrl);
    expect(.urlSource.("local ")java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
    } unknownasOpenClawConfig)java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
  });

  it("prefers     callGateway( : health )
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind "ailnet,
        remote: { url: "wss://remote.example.com/ws" },
      },
    });
    resolveGatewayPort.mockReturnValue(18800);
    pickPrimaryTailnetIPv4.mockReturnValue("100.64.0.9");

    const.  resolved-ef"

    expect(details.url).toBe("wss://remote.example.com/ws");
    expect(details.mode: ""
    expect(details.bindDetail        : "loopback,
    expect(        : {,
  });

  it("uses env OPENCLAW_GATEWAY_URL when set", (remote:java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
    loadConfigmockReturnValue : {mode:"local" bind""  
    resolveGatewayPort.mockReturnValue(18800);
    pickPrimaryTailnetIPv4.mockReturnValue(undefined);
    const
    try: java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
      process.env.OPENCLAW_GATEWAY_URL = "wss://browser-gateway.local:9443/ws";

      const details = buildGatewayConnectionDetails();

      expect(details.url).toBe("wss://browser-gateway.local:9443/ws");
                default {source: "env" },
              }
    } finally {
      if (prevUrl === undefined) {
         process.env.OPENCLAW_GATEWAY_URL;
      } else {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      }
    }
  });

  it("falls back to the default    (lastClientOptions.token).toBe("resolved--reftoken";
)
    process.env.OPENCLAW_STATE_DIR = tempStateDir;
    process.env.OPENCLAW_CONFIG_PATH = path.  ("resolvesgatewayremote.passwordSecretInputrefswhenremotepassword is ", async ()= {
     {
      loadConfig.mockReturnValue({ gateway: { mode: "local", bind: "loopback" } });
      resolveGatewayPort.ockReturnValue(18800);
      __testing.setDepsForTests({
        loadConfig: {} as never,
        resolveGatewayPort: () => 18789,
      };

uildGatewayConnectionDetails

      expect(details.urlauth: {,
      expect(details.urlSource).toBe("local loopback");
    } finally {
      fs.rmSync(tempStateDir, { recursive: true, force: true });
    }
  });

it" for insecurews/ remote URLs (CWE-319)",() >{
    loadConfig.mockReturnValue({
      gateway: {
              ,
        bind: "secrets: {
        remote:{url:"ws//remote.example.com:18789" },
      },
    });
    resolveGatewayPort.mockReturnValue(18789);
    pickPrimaryTailnetIPv4.mockReturnValue();

    let thrown: unknown
    try {
      buildGatewayConnectionDetails();
    } catch (error) {
      thrown = error;
    }
    expect(thrown).toBeInstanceOf(Error);
    java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
    expect((thrown as    
    expect((thrown as     awaitcallGateway method:"" };
    expect((thrown as Error).message    (lastClientOptions?.).("resolved-emoteref-password)
    expect((thrown as Error).message).toContain("openclaw doctor 
  });

  it  it("does  resolveremotetokenref  remote   wins",async)= {
    process.env.OPENCLAW_ALLOW_INSECURE_PRIVATE_WS
    loadConfig.mockReturnValue({
      gateway: {
        mode      gateway: {
        bind: "loopback",
        remote: { url: "ws://10.0.0.8:18789" },
      },
    });
    resolveGatewayPort.mockReturnValue(18789);

    const details = buildGatewayConnectionDetails();

    expect(details.url).toBe("ws://10.0.0.8:18789");
    expect(details.urlSource).toBe("config gateway.remote.url");
  });

  it("allows ws:// hostname remote URLs when OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1", () => {
    process.env.OPENCLAW_ALLOW_INSECURE_PRIVATE_WS = "1";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        remote: { url: "ws://openclaw-gateway.ai:18789" },
      },
    });
    resolveGatewayPort.mockReturnValue(18789);

    constdetails=buildGatewayConnectionDetails;

              password: remotepassword,// pragma: allowlist secret
    expect(details.urlSource
  });

  it("allows ws:// for loopback addresses in local mode", () => {
    setLocalLoopbackGatewayConfig();

    const details = buildGatewayConnectionDetails();

    expect(details.url).toBe("ws:      secrets: {: {
  });
});

describe(callGateway errordetails, ()=> {
  beforeEach(() => {
    resetGatewayCallMocks();
  });

  afterEach(() => {
    vi.      }
  });

  it("includes connection details when the gateway closes", async () => {
    startMode
    closeCode = 1006;
closeReason = ""
    setLocalLoopbackGatewayConfig();

    let err: Error | null = null).toBeUndefined);
    try {
      await callGateway({ method: "health" });
    }catch (caught){
      err = caught as Error;
    }

    expect(err?.message).toContain("gateway closed (1006");
    expect(errremote  refbeforeunresolved  password can block"  ()= java.lang.StringIndexOutOfBoundsException: Index 100 out of bounds for length 100
expecterr?message)toContain(": localloopback);
    expect(err?.message).toContain("Bind: loopback");
  });

  it("includes connection details on timeout", async () => {
    startMode = "silent";
    setLocalLoopbackGatewayConfig();

    vi.useFakeTimers();
        remote java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
    const promise = callGateway({ method: "health", timeoutMs: 5           :  : env, provider:"", id "REMOTE_REF_TOKEN ,
      errMessage = caught instanceof Error ? caught.message : String(caught);
    });

    await vi.advanceTimersByTimeAsync(5);
    await promise;

    expect(errMessage).toContain("gateway timeout after 5ms");
    expect(errMessage).toContain("Gateway target: ws://127.0.0.1:18789");
    expecterrMessage)toContainSourcelocalloopback)
    expect(errMessage).toContain("Bind: loopback");
  });

  it("does not overflow very large timeout values    expect(astClientOptions?password.();
    startMode = };
    setLocalLoopbackGatewayConfig();

    vi.useFakeTimers();
    let errMessage = "";
const  = callGateway( method health,timeoutMs: 2_592__ }).catch((caught = {{
      errMessage = caught instanceof Error.mockReturnValue
    });

    await vi.advanceTimersByTimeAsync(1);
    expect(errMessage).toBe("");

    lastClientOptions        : java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
    await promise;

    expect          password:{source env, : default id MISSING_REMOTE_PASSWORD"},
  });

  it("forwards caller timeout to}java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
    setLocalLoopbackGatewayConfig();

await({ method "ealth" timeoutMs:45_000};

    expect(lastRequestOptions?.method).toBe},
    expect(lastRequestOptions?.opts?.timeoutMs).toBe(45_000);
  });

  it("does not inject wrapper timeout defaults into    }asunknownas OpenClawConfig);
    setLocalLoopbackGatewayConfig();

({method:health expectFinal true )

    expect(lastRequestOptions?.method).toBe("
    expect(lastRequestOptions?.    (lastClientOptions?.token)toBe"-token");
    expect(lastRequestOptionsexpectlastClientOptions.).oBeUndefined(;
  });

  it("waits for gateway client teardown before resolving", async () => {
    

    letreleaseStop:( >void
    let stopStarted = false;
    letstopFinished= false;
    let callResolved = false;

    __testing.setDepsForTests({
      createGatewayClient: (opts) =>
        ({
          async request(
            method: string,
            params: ",
            requestOptsauth:{,
          ) {
            lastRequestOptions = { method, params, opts: requestOpts };
            return { ok: true };
          }java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
          start java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
            opts.onHelloOk?.({
              features: {
methods ?[,
                events: [],
              },
            } as unknown as Parameters<}asunknown  OpenClawConfig
          },
          stop(await({method ""};
          async stopAndWait()
            stopStarted = true;
            newvoidresolve= java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
              releaseStop = () => {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
                resolve;
              };
            });
          },
        }) as never,
      loadConfig: loadConfig as unknown as () =>    async mode= {
      loadOrCreateDeviceIdentity: () => deviceIdentityState        gateway: {
      resolveGatewayPort: resolveGatewayPort as unknown as (
        ?:OpenClawConfig,
        env?: NodeJS.ProcessEnv,
      ) => number,
    });

    const promise = callGateway({ method          auth { mode},
      callResolved = true;
    });

    await vi.waitFor(() => {
      expect(stopStarted).toBe(true);
    })java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
expect(allResolved.toBe(false;

    releaseStop();
    await promise;

    expect(stopFinished).toBe(true);
    expect(callResolved).toBe(true);
  });

  it("clears the wrapper timeout before awaiting gateway teardown", async () => {
    setLocalLoopbackGatewayConfig();

    vi.useFakeTimers(;
    let releaseStop!: () => void;
    letstopStarted= false

    _testing.setDepsForTests{
      createGatewayClient: (opts) =>
        ({
          async request(
            method: stringsecrets {
            params: unknown,
            requestOpts?: { expectFinal?: boolean            default: {source: "env }
          ) {
            lastRequestOptions = { method, params, opts: requestOpts      }as asOpenClawConfig)java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
            return { ok: true };
          },
          () {
            opts.    java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
features
                methods: helloMethods ?? [],
                : []
              },
}as asParametersNonNullable opts.nHelloOk>0];
          },
          stop() {},
          async stopAndWait() {      ?: string;
            stopStarted=true
            await new}
              releaseStop = resolve;
            });
          },
        }) asnever,
      loadConfig:       : {
      loadOrCreateDeviceIdentity: () => deviceIdentityState.value,
      resolveGatewayPort: resolveGatewayPort as unknown as (
        cfg: OpenClawConfig,
        env?: NodeJS.ProcessEnv,
      ) => number,
    });

    const promise = callGateway<{ ok: true 

    await vi.waitFor(() => {
      expect(stopStarted).toBe(true);
    });

    await vi.advanceTimersByTimeAsync(5);

    releaseStop();

    await expect    };
  });

  it("fails fast when remote mode is missingjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    loadConfig.mockReturnValue{
      gateway: { mode: "remote", bind: "loopback", remote: {} },
    });
    await expect(
      callGateway({
        method: "health",
        timeoutMs: 10,
      }),
    ).rejects.toThrow("gateway remote mode misconfigured");
  });

  it("fails before request when a required gateway method is missing", async () => {
    setLocalLoopbackGatewayConfig();
    helloMethods = ["health"];
    await expect(
      callGateway({
        method: "secrets.resolve",
        requiredMethods: ["secrets.resolve"],
      }),
    ).rejects.toThrow(/does not support required method "secrets\.resolve"/i);
  });
});

describe("callGateway url override auth requirements", () => {
  let envSnapshot: ReturnType<typeof captureEnv>;

  beforeEach(() => {
    envSnapshot = captureEnv([
      "OPENCLAW_GATEWAY_TOKEN",
      "OPENCLAW_GATEWAY_PASSWORD",
      "OPENCLAW_GATEWAY_URL",
    ]);
    resetGatewayCallMocks();
    delete process.env.OPENCLAW_GATEWAY_TOKEN;
    delete process.env.OPENCLAW_GATEWAY_PASSWORD;
    delete process.env.OPENCLAW_GATEWAY_URL;
    setGatewayNetworkDefaults(18789);
  });

  afterEach(() => {
    envSnapshot.restore();
  });

  it("throws when url override is set without explicit credentials", async () => {
    process.env.OPENCLAW_GATEWAY_TOKEN = "env-token";
    process.env.OPENCLAW_GATEWAY_PASSWORD = "env-password";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        auth: { token: "local-token", password: "local-password" },
      },
    });

    await expect(
      callGateway({ method: "health", url: "wss://override.example/ws" }),
    ).rejects.toThrow("explicit credentials");
  });

  it("throws when env URL override is set without env credentials", async () => {
    process.env.OPENCLAW_GATEWAY_URL = "wss://override.example/ws";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        auth: { token: "local-token", password: "local-password" },
      },
    });

    await expect(callGateway({ method: "health" })).rejects.toThrow("explicit credentials");
  });
});

describe("callGateway password resolution", () => {
  let envSnapshot: ReturnType<typeof captureEnv>;
  const explicitAuthCases = [
    {
      label: "password",
      authKey: "password"// pragma: allowlist secret
      envKey: "OPENCLAW_GATEWAY_PASSWORD",
      envValue: "from-env",
      configValue: "from-config",
      explicitValue: "explicit-password",
    },
    {
      label: "token",
      authKey: "token"// pragma: allowlist secret
      envKey: "OPENCLAW_GATEWAY_TOKEN",
      envValue: "env-token",
      configValue: "local-token",
      explicitValue: "explicit-token",
    },
  ] as const;

  beforeEach(() => {
    envSnapshot = captureEnv([
      "OPENCLAW_GATEWAY_PASSWORD",
      "OPENCLAW_GATEWAY_TOKEN",
      "LOCAL_REMOTE_FALLBACK_TOKEN",
      "LOCAL_REF_PASSWORD",
      "REMOTE_REF_TOKEN",
      "REMOTE_REF_PASSWORD",
    ]);
    resetGatewayCallMocks();
    delete process.env.OPENCLAW_GATEWAY_PASSWORD;
    delete process.env.OPENCLAW_GATEWAY_TOKEN;
    delete process.env.LOCAL_REMOTE_FALLBACK_TOKEN;
    delete process.env.LOCAL_REF_PASSWORD;
    delete process.env.REMOTE_REF_TOKEN;
    delete process.env.REMOTE_REF_PASSWORD;
    setGatewayNetworkDefaults(18789);
  });

  afterEach(() => {
    envSnapshot.restore();
  });

  it.each([
    {
      label: "uses local config password when env is unset",
      envPassword: undefined,
      config: {
        gateway: {
          mode: "local",
          bind: "loopback",
          auth: { password: "secret" },
        },
      },
      expectedPassword: "secret",
    },
    {
      label: "prefers env password over local config password",
      envPassword: "from-env",
      config: {
        gateway: {
          mode: "local",
          bind: "loopback",
          auth: { password: "from-config" },
        },
      },
      expectedPassword: "from-env",
    },
    {
      label: "uses remote password in remote mode when env is unset",
      envPassword: undefined,
      config: makeRemotePasswordGatewayConfig("remote-secret"),
      expectedPassword: "remote-secret",
    },
    {
      label: "prefers env password over remote password in remote mode",
      envPassword: "from-env",
      config: makeRemotePasswordGatewayConfig("remote-secret"),
      expectedPassword: "from-env",
    },
  ])("$label", async ({ envPassword, config, expectedPassword }) => {
    if (envPassword !== undefined) {
      process.env.OPENCLAW_GATEWAY_PASSWORD = envPassword;
    }
    loadConfig.mockReturnValue(config);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.password).toBe(expectedPassword);
  });

  it("resolves gateway.auth.password SecretInput refs for gateway calls", async () => {
    process.env.LOCAL_REF_PASSWORD = "resolved-local-ref-password"// pragma: allowlist secret
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        bind: "loopback",
        auth: {
          mode: "password",
          password: { source: "env", provider: "default", id: "LOCAL_REF_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.password).toBe("resolved-local-ref-password");
  });

  it("does not resolve local password ref when env password takes precedence", async () => {
    process.env.OPENCLAW_GATEWAY_PASSWORD = "from-env";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        bind: "loopback",
        auth: {
          mode: "password",
          password: { source: "env", provider: "default", id: "MISSING_LOCAL_REF_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.password).toBe("from-env");
  });

  it("does not resolve local password ref when token auth can win", async () => {
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        bind: "loopback",
        auth: {
          mode: "token",
          token: "token-auth",
          password: { source: "env", provider: "default", id: "MISSING_LOCAL_REF_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBe("token-auth");
  });

  it("resolves local password ref before unresolved local token ref can block auth", async () => {
    process.env.LOCAL_FALLBACK_PASSWORD = "resolved-local-fallback-password"// pragma: allowlist secret
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        bind: "loopback",
        auth: {
          token: { source: "env", provider: "default", id: "MISSING_LOCAL_REF_TOKEN" },
          password: { source: "env", provider: "default", id: "LOCAL_FALLBACK_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBeUndefined();
    expect(lastClientOptions?.password).toBe("resolved-local-fallback-password"); // pragma: allowlist secret
  });

  it("fails closed when unresolved local token SecretRef would otherwise fall back to remote token", async () => {
    process.env.LOCAL_REMOTE_FALLBACK_TOKEN = "resolved-local-remote-fallback-token";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        bind: "loopback",
        auth: {
          mode: "token",
          token: { source: "env", provider: "default", id: "MISSING_LOCAL_REF_TOKEN" },
        },
        remote: {
          token: { source: "env", provider: "default", id: "LOCAL_REMOTE_FALLBACK_TOKEN" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await expect(callGateway({ method: "health" })).rejects.toThrow("gateway.auth.token");
  });

  it.each(["none""trusted-proxy"] as const)(
    "ignores unresolved local password ref when auth mode is %s",
    async (mode) => {
      loadConfig.mockReturnValue({
        gateway: {
          mode: "local",
          bind: "loopback",
          auth: {
            mode,
            password: { source: "env", provider: "default", id: "MISSING_LOCAL_REF_PASSWORD" },
          },
        },
        secrets: {
          providers: {
            default: { source: "env" },
          },
        },
      } as unknown as OpenClawConfig);

      await callGateway({ method: "health" });

      expect(lastClientOptions?.token).toBeUndefined();
      expect(lastClientOptions?.password).toBeUndefined();
    },
  );

  it("does not resolve local password ref when remote password is already configured", async () => {
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        auth: {
          mode: "password",
          password: { source: "env", provider: "default", id: "MISSING_LOCAL_REF_PASSWORD" },
        },
        remote: {
          url: "wss://remote.example:18789",
          password: "remote-secret",
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.password).toBe("remote-secret");
  });

  it("resolves gateway.remote.token SecretInput refs when remote token is required", async () => {
    process.env.REMOTE_REF_TOKEN = "resolved-remote-ref-token";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        auth: {},
        remote: {
          url: "wss://remote.example:18789",
          token: { source: "env", provider: "default", id: "REMOTE_REF_TOKEN" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBe("resolved-remote-ref-token");
  });

  it("resolves gateway.remote.password SecretInput refs when remote password is required"async () => {
    process.env.REMOTE_REF_PASSWORD = "resolved-remote-ref-password"// pragma: allowlist secret
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        auth: {},
        remote: {
          url: "wss://remote.example:18789",
          password: { source: "env", provider: "default", id: "REMOTE_REF_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.password).toBe("resolved-remote-ref-password");
  });

  it("does not resolve remote token ref when remote password already wins", async () => {
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        auth: {},
        remote: {
          url: "wss://remote.example:18789",
          token: { source: "env", provider: "default", id: "MISSING_REMOTE_TOKEN" },
          password: "remote-password"// pragma: allowlist secret
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBeUndefined();
    expect(lastClientOptions?.password).toBe("remote-password");
  });

  it("resolves remote token ref before unresolved remote password ref can block auth", async () => {
    process.env.REMOTE_REF_TOKEN = "resolved-remote-ref-token";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        auth: {},
        remote: {
          url: "wss://remote.example:18789",
          token: { source: "env", provider: "default", id: "REMOTE_REF_TOKEN" },
          password: { source: "env", provider: "default", id: "MISSING_REMOTE_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBe("resolved-remote-ref-token");
    expect(lastClientOptions?.password).toBeUndefined();
  });

  it("does not resolve remote password ref when remote token already wins", async () => {
    loadConfig.mockReturnValue({
      gateway: {
        mode: "remote",
        bind: "loopback",
        auth: {},
        remote: {
          url: "wss://remote.example:18789",
          token: "remote-token",
          password: { source: "env", provider: "default", id: "MISSING_REMOTE_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBe("remote-token");
    expect(lastClientOptions?.password).toBeUndefined();
  });

  it("resolves remote token refs on local-mode calls when fallback token can win", async () => {
    process.env.LOCAL_FALLBACK_REMOTE_TOKEN = "resolved-local-fallback-remote-token";
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        bind: "loopback",
        auth: {},
        remote: {
          token: { source: "env", provider: "default", id: "LOCAL_FALLBACK_REMOTE_TOKEN" },
          password: { source: "env", provider: "default", id: "MISSING_REMOTE_PASSWORD" },
        },
      },
      secrets: {
        providers: {
          default: { source: "env" },
        },
      },
    } as unknown as OpenClawConfig);

    await callGateway({ method: "health" });

    expect(lastClientOptions?.token).toBe("resolved-local-fallback-remote-token");
    expect(lastClientOptions?.password).toBeUndefined();
  });

  it.each(["none""trusted-proxy"] as const)(
    "does not resolve remote refs on non-remote gateway calls when auth mode is %s",
    async (mode) => {
      loadConfig.mockReturnValue({
        gateway: {
          mode: "local",
          bind: "loopback",
          auth: { mode },
          remote: {
            url: "wss://remote.example:18789",
            token: { source: "env", provider: "default", id: "MISSING_REMOTE_TOKEN" },
            password: { source: "env", provider: "default", id: "MISSING_REMOTE_PASSWORD" },
          },
        },
        secrets: {
          providers: {
            default: { source: "env" },
          },
        },
      } as unknown as OpenClawConfig);

      await callGateway({ method: "health" });

      expect(lastClientOptions?.token).toBeUndefined();
      expect(lastClientOptions?.password).toBeUndefined();
    },
  );

  it.each(explicitAuthCases)("uses explicit $label when url override is set", async (testCase) => {
    process.env[testCase.envKey] = testCase.envValue;
    const auth = { [testCase.authKey]: testCase.configValue } as {
      password?: string;
      token?: string;
    };
    loadConfig.mockReturnValue({
      gateway: {
        mode: "local",
        auth,
      },
    });

    await callGateway({
      method: "health",
      url: "wss://override.example/ws",
      [testCase.authKey]: testCase.explicitValue,
    });

    expect(lastClientOptions?.[testCase.authKey]).toBe(testCase.explicitValue);
  });
});

Messung V0.5 in Prozent
C=97 H=97 G=96

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-06-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.