mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 04:47:03 -06:00
fix(signal): reuse effective managed transport
This commit is contained in:
@@ -378,6 +378,54 @@ describe("Signal existing-server setup", () => {
|
||||
expect(queued.note).toHaveBeenCalledWith(expect.stringContaining("not ready"), "Signal setup");
|
||||
});
|
||||
|
||||
it("does not persist an unverified alias of a configured managed daemon", async () => {
|
||||
mocks.probeSignalTransport.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 200,
|
||||
failureKind: "unverifiable-single-account",
|
||||
error: "server account cannot be verified",
|
||||
});
|
||||
const cfg: OpenClawConfig = {
|
||||
channels: {
|
||||
signal: {
|
||||
account: "+15555550123",
|
||||
transport: { kind: "managed-native", httpHost: "127.0.0.1", httpPort: 8080 },
|
||||
},
|
||||
},
|
||||
};
|
||||
const queued = createQueuedWizardPrompter({
|
||||
selectValues: ["existing-server", "stop"],
|
||||
textValues: ["http://custom-hosts-alias:8080"],
|
||||
});
|
||||
const prepared = await runSetupWizardPrepare({
|
||||
prepare: signalSetupWizard.prepare,
|
||||
cfg,
|
||||
prompter: queued.prompter,
|
||||
runtime: createRuntimeEnv({ throwOnExit: false }),
|
||||
});
|
||||
|
||||
await expect(
|
||||
runSetupWizardFinalize({
|
||||
finalize: signalSetupWizard.finalize,
|
||||
cfg,
|
||||
credentialValues: toCredentialValues(prepared?.credentialValues),
|
||||
prompter: queued.prompter,
|
||||
runtime: createRuntimeEnv({ throwOnExit: false }),
|
||||
}),
|
||||
).rejects.toBeInstanceOf(WizardCancelledError);
|
||||
|
||||
expect(queued.confirm).not.toHaveBeenCalled();
|
||||
expect(cfg.channels?.signal?.transport).toEqual({
|
||||
kind: "managed-native",
|
||||
httpHost: "127.0.0.1",
|
||||
httpPort: 8080,
|
||||
});
|
||||
expect(queued.note).toHaveBeenCalledWith(
|
||||
expect.stringContaining("server account cannot be verified"),
|
||||
"Signal setup",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects an alias of a managed daemon and accepts an independent server", async () => {
|
||||
mocks.networkInterfaces.mockImplementationOnce(() => {
|
||||
throw new Error("interface enumeration denied");
|
||||
|
||||
@@ -10,7 +10,10 @@ import type { SignalDaemonHandle } from "./daemon.js";
|
||||
import { registerSignalManagedDaemonOwner } from "./managed-daemon-runtime-context.js";
|
||||
import { setSignalRuntime } from "./runtime.js";
|
||||
import { clearSignalRuntimeForTest } from "./runtime.test-support.js";
|
||||
import type { SignalTransportProbeResult } from "./setup-transport.js";
|
||||
import type {
|
||||
SignalManagedNativeTransport,
|
||||
SignalTransportProbeResult,
|
||||
} from "./setup-transport.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
assertBindAvailable: vi.fn(async () => undefined),
|
||||
@@ -65,7 +68,7 @@ const transport = {
|
||||
|
||||
function createParams(
|
||||
cfg: OpenClawConfig = {},
|
||||
candidate: typeof transport | (typeof transport & { url: string }) = transport,
|
||||
candidate: SignalManagedNativeTransport = transport,
|
||||
reusableAccount?: string,
|
||||
) {
|
||||
return {
|
||||
@@ -182,6 +185,46 @@ describe("probeManagedSignalSetup", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("reuses the monitor-owned effective transport when config only names the account", async () => {
|
||||
const cfg = {
|
||||
channels: { signal: { accounts: { work: { account } } } },
|
||||
} as OpenClawConfig;
|
||||
const effectiveTransport = {
|
||||
kind: "managed-native" as const,
|
||||
cliPath: "signal-cli",
|
||||
httpHost: "127.0.0.1",
|
||||
httpPort: 8080,
|
||||
};
|
||||
const lifecycle = createSignalDaemonLifecycle({});
|
||||
const handle = mocks.spawnDaemon();
|
||||
mocks.spawnDaemon.mockClear();
|
||||
lifecycle.attach(handle);
|
||||
registerSignalManagedDaemonOwner({
|
||||
handle,
|
||||
owner: {
|
||||
accountId: "work",
|
||||
account,
|
||||
cliPath: effectiveTransport.cliPath,
|
||||
httpHost: effectiveTransport.httpHost,
|
||||
httpPort: effectiveTransport.httpPort,
|
||||
},
|
||||
abortSignal: lifecycle.abortSignal,
|
||||
});
|
||||
|
||||
try {
|
||||
await expect(
|
||||
probeManagedSignalSetup(createParams(cfg, effectiveTransport, account)),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
expect(mocks.probeTransport).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ nativeAccountBinding: "owner-known-bound-account" }),
|
||||
);
|
||||
expect(mocks.assertBindAvailable).not.toHaveBeenCalled();
|
||||
expect(mocks.spawnDaemon).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
await lifecycle.stop();
|
||||
}
|
||||
});
|
||||
|
||||
it("does not trust an unverifiable listener as the configured account", async () => {
|
||||
const cfg = {
|
||||
channels: { signal: { accounts: { work: { account, transport } } } },
|
||||
|
||||
@@ -8,7 +8,6 @@ import { isSignalManagedDaemonOwned } from "./managed-daemon-runtime-context.js"
|
||||
import { assertSignalSetupDaemonBindAvailable } from "./setup-daemon-bind.js";
|
||||
import {
|
||||
probeSignalTransport,
|
||||
resolveConfiguredSignalTransport,
|
||||
type SignalManagedNativeTransport,
|
||||
type SignalTransportProbeResult,
|
||||
} from "./setup-transport.js";
|
||||
@@ -130,23 +129,19 @@ export async function probeManagedSignalSetup(params: {
|
||||
let daemon: ReturnType<typeof spawnSignalDaemon> | undefined;
|
||||
let result: SignalTransportProbeResult = { ok: false, error: "Signal transport probe failed." };
|
||||
try {
|
||||
const configured = resolveConfiguredSignalTransport(params.cfg, params.accountId);
|
||||
const configuredAccountInfo = resolveSignalAccount({
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
const configured = configuredAccountInfo.transport;
|
||||
const configuredAccount = normalizeOptionalString(configuredAccountInfo.config.account);
|
||||
if (
|
||||
configured?.kind === "managed-native" &&
|
||||
configured.kind === "managed-native" &&
|
||||
configuredAccount === params.account &&
|
||||
params.reusableConfiguredAccount === params.account &&
|
||||
params.reusableConfiguredTransport === managedSignalTransportIdentity(configured)
|
||||
) {
|
||||
const configuredResolved = resolveSignalTransport(configured);
|
||||
if (
|
||||
configuredResolved.kind === "managed-native" &&
|
||||
sameManagedTransport(configuredResolved, resolved)
|
||||
) {
|
||||
if (sameManagedTransport(configured, resolved)) {
|
||||
const ownerKnown = isSignalManagedDaemonOwned({
|
||||
accountId: configuredAccountInfo.accountId,
|
||||
account: params.account,
|
||||
|
||||
Reference in New Issue
Block a user