mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-16 19:29:26 +02:00
fix: preserve openclaw gateway token mask
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
63
packages/core/agents/openclaw-runtime-config.test.ts
Normal file
63
packages/core/agents/openclaw-runtime-config.test.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
OPENCLAW_GATEWAY_TOKEN_MASK,
|
||||
serializeOpenclawRuntimeConfig,
|
||||
} from "./openclaw-runtime-config";
|
||||
|
||||
describe("serializeOpenclawRuntimeConfig", () => {
|
||||
it("keeps the masked gateway token sentinel so the API can preserve the persisted token", () => {
|
||||
expect(
|
||||
serializeOpenclawRuntimeConfig({
|
||||
mode: "gateway",
|
||||
gateway: {
|
||||
host: "gw.internal",
|
||||
port: 18789,
|
||||
token: OPENCLAW_GATEWAY_TOKEN_MASK,
|
||||
tls: true,
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
mode: "gateway",
|
||||
gateway: {
|
||||
host: "gw.internal",
|
||||
port: 18789,
|
||||
token: OPENCLAW_GATEWAY_TOKEN_MASK,
|
||||
tls: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("omits an empty gateway token so users can clear a persisted token", () => {
|
||||
expect(
|
||||
serializeOpenclawRuntimeConfig({
|
||||
mode: "gateway",
|
||||
gateway: {
|
||||
host: "gw.internal",
|
||||
port: 18789,
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
mode: "gateway",
|
||||
gateway: {
|
||||
host: "gw.internal",
|
||||
port: 18789,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("passes through a real gateway token value", () => {
|
||||
expect(
|
||||
serializeOpenclawRuntimeConfig({
|
||||
mode: "gateway",
|
||||
gateway: {
|
||||
token: "rotated-secret",
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
mode: "gateway",
|
||||
gateway: {
|
||||
token: "rotated-secret",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -20,10 +20,9 @@ export interface OpenclawRuntimeConfig {
|
||||
}
|
||||
|
||||
// Sentinel the API substitutes for a non-empty `gateway.token` on every read.
|
||||
// When the form re-submits the same sentinel we strip the field client-side
|
||||
// so the backend's matching preserve hook restores the persisted token
|
||||
// instead of overwriting it. Mirrors `runtimeConfigGatewayTokenMask` in
|
||||
// server/internal/handler/agent.go.
|
||||
// When the form re-submits the same sentinel, the backend's matching
|
||||
// preserve hook restores the persisted token instead of overwriting it.
|
||||
// Mirrors `runtimeConfigGatewayTokenMask` in server/internal/handler/agent.go.
|
||||
export const OPENCLAW_GATEWAY_TOKEN_MASK = "***";
|
||||
|
||||
// Parse an arbitrary runtime_config payload into the typed schema. Unknown
|
||||
@@ -65,12 +64,10 @@ export function serializeOpenclawRuntimeConfig(
|
||||
if (cfg.gateway.host) gw.host = cfg.gateway.host;
|
||||
if (cfg.gateway.port) gw.port = cfg.gateway.port;
|
||||
if (cfg.gateway.tls) gw.tls = true;
|
||||
// The mask sentinel must NEVER round-trip back to the server; the
|
||||
// matching preserve hook on the backend treats its presence as "keep
|
||||
// the persisted token", but emitting it here would still hit the wire
|
||||
// and trip any future schema validation. Drop it client-side so the
|
||||
// payload genuinely omits the field.
|
||||
if (cfg.gateway.token && cfg.gateway.token !== OPENCLAW_GATEWAY_TOKEN_MASK) {
|
||||
// The mask sentinel is the explicit "keep persisted token" signal for
|
||||
// the API. Omitting the field means "clear/no token" for partial
|
||||
// gateway pins, so the sentinel must survive serialization.
|
||||
if (cfg.gateway.token) {
|
||||
gw.token = cfg.gateway.token;
|
||||
}
|
||||
if (Object.keys(gw).length > 0) out.gateway = gw;
|
||||
|
||||
Reference in New Issue
Block a user