Skip to content

Commit 18a5683

Browse files
committed
Auto-merge upstream openclaw/openclaw
2 parents d0690f3 + 29a5679 commit 18a5683

20 files changed

Lines changed: 1546 additions & 185 deletions

src/commands/doctor/shared/legacy-x-search-migrate.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,42 @@ describe("legacy x_search config migration", () => {
8080
});
8181
});
8282

83+
it("moves legacy x_search SecretRefs into the xai plugin auth slot unchanged", () => {
84+
const res = migrateLegacyXSearchConfig({
85+
tools: {
86+
web: {
87+
x_search: {
88+
apiKey: {
89+
source: "env",
90+
provider: "default",
91+
id: "X_SEARCH_KEY_REF",
92+
},
93+
enabled: true,
94+
},
95+
} as Record<string, unknown>,
96+
},
97+
} as OpenClawConfig);
98+
99+
expect((res.config.tools?.web as Record<string, unknown> | undefined)?.x_search).toEqual({
100+
enabled: true,
101+
});
102+
expect(res.config.plugins?.entries?.xai).toEqual({
103+
enabled: true,
104+
config: {
105+
webSearch: {
106+
apiKey: {
107+
source: "env",
108+
provider: "default",
109+
id: "X_SEARCH_KEY_REF",
110+
},
111+
},
112+
},
113+
});
114+
expect(res.changes).toEqual([
115+
"Moved tools.web.x_search.apiKey → plugins.entries.xai.config.webSearch.apiKey.",
116+
]);
117+
});
118+
83119
it("does nothing for knob-only x_search config without a legacy apiKey", () => {
84120
const config = {
85121
tools: {

src/config/channel-configured.test.ts

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,9 @@
11
import fs from "node:fs";
2-
import os from "node:os";
32
import path from "node:path";
4-
import { afterEach, describe, expect, it } from "vitest";
3+
import { describe, expect, it } from "vitest";
4+
import { withTempDirSync } from "../test-helpers/temp-dir.js";
55
import { isChannelConfigured } from "./channel-configured.js";
66

7-
const tempDirs: string[] = [];
8-
9-
function makeTempStateDir() {
10-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-channel-configured-"));
11-
tempDirs.push(dir);
12-
return dir;
13-
}
14-
15-
afterEach(() => {
16-
while (tempDirs.length > 0) {
17-
const dir = tempDirs.pop();
18-
if (dir) {
19-
fs.rmSync(dir, { recursive: true, force: true });
20-
}
21-
}
22-
});
23-
247
describe("isChannelConfigured", () => {
258
it("detects Telegram env configuration through the package metadata seam", () => {
269
expect(isChannelConfigured({}, "telegram", { TELEGRAM_BOT_TOKEN: "token" })).toBe(true);
@@ -61,18 +44,19 @@ describe("isChannelConfigured", () => {
6144
});
6245

6346
it("detects persisted Matrix credentials through package metadata", () => {
64-
const stateDir = makeTempStateDir();
65-
fs.mkdirSync(path.join(stateDir, "credentials", "matrix"), { recursive: true });
66-
fs.writeFileSync(
67-
path.join(stateDir, "credentials", "matrix", "credentials-ops.json"),
68-
JSON.stringify({
69-
homeserver: "https://matrix.example.org",
70-
userId: "@ops:example.org",
71-
accessToken: "token",
72-
}),
73-
"utf8",
74-
);
75-
76-
expect(isChannelConfigured({}, "matrix", { OPENCLAW_STATE_DIR: stateDir })).toBe(true);
47+
withTempDirSync({ prefix: "openclaw-channel-configured-" }, (stateDir) => {
48+
fs.mkdirSync(path.join(stateDir, "credentials", "matrix"), { recursive: true });
49+
fs.writeFileSync(
50+
path.join(stateDir, "credentials", "matrix", "credentials-ops.json"),
51+
JSON.stringify({
52+
homeserver: "https://matrix.example.org",
53+
userId: "@ops:example.org",
54+
accessToken: "token",
55+
}),
56+
"utf8",
57+
);
58+
59+
expect(isChannelConfigured({}, "matrix", { OPENCLAW_STATE_DIR: stateDir })).toBe(true);
60+
});
7761
});
7862
});

src/config/config-misc.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,41 @@ describe("config strict validation", () => {
651651
});
652652
});
653653

654+
it("accepts legacy x_search SecretRefs via auto-migration and reports legacyIssues", async () => {
655+
await withTempHome(async (home) => {
656+
await writeOpenClawConfig(home, {
657+
tools: {
658+
web: {
659+
x_search: {
660+
apiKey: {
661+
source: "env",
662+
provider: "default",
663+
id: "X_SEARCH_KEY_REF",
664+
},
665+
},
666+
},
667+
},
668+
});
669+
670+
const snap = await readConfigFileSnapshot();
671+
672+
expect(snap.valid).toBe(true);
673+
expect(snap.legacyIssues.some((issue) => issue.path === "tools.web.x_search.apiKey")).toBe(
674+
true,
675+
);
676+
expect(snap.sourceConfig.plugins?.entries?.xai?.config?.webSearch).toMatchObject({
677+
apiKey: {
678+
source: "env",
679+
provider: "default",
680+
id: "X_SEARCH_KEY_REF",
681+
},
682+
});
683+
expect(
684+
(snap.sourceConfig.tools?.web?.x_search as Record<string, unknown> | undefined)?.apiKey,
685+
).toBeUndefined();
686+
});
687+
});
688+
654689
it("accepts legacy thread binding ttlHours via auto-migration and reports legacyIssues", async () => {
655690
await withTempHome(async (home) => {
656691
await writeOpenClawConfig(home, {

src/config/doc-baseline.integration.test.ts

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from "node:fs/promises";
2-
import os from "node:os";
32
import path from "node:path";
4-
import { afterEach, describe, expect, it } from "vitest";
3+
import { describe, expect, it } from "vitest";
4+
import { withTempDir } from "../test-helpers/temp-dir.js";
55
import {
66
type ConfigDocBaselineEntry,
77
flattenConfigDocBaselineEntries,
@@ -10,7 +10,6 @@ import {
1010
} from "./doc-baseline.js";
1111

1212
describe("config doc baseline integration", () => {
13-
const tempRoots: string[] = [];
1413
let sharedRenderedPromise: Promise<
1514
Awaited<ReturnType<typeof renderConfigDocBaselineArtifacts>>
1615
> | null = null;
@@ -29,14 +28,6 @@ describe("config doc baseline integration", () => {
2928
return sharedByPathPromise;
3029
}
3130

32-
afterEach(async () => {
33-
await Promise.all(
34-
tempRoots.splice(0).map(async (tempRoot) => {
35-
await fs.rm(tempRoot, { recursive: true, force: true });
36-
}),
37-
);
38-
});
39-
4031
it("is deterministic across repeated runs", async () => {
4132
const { baseline } = await getSharedRendered();
4233
const first = await renderConfigDocBaselineArtifacts(baseline);
@@ -121,36 +112,36 @@ describe("config doc baseline integration", () => {
121112
});
122113

123114
it("supports check mode for stale hash files", async () => {
124-
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-config-doc-baseline-"));
125-
tempRoots.push(tempRoot);
126-
const rendered = getSharedRendered();
127-
128-
const initial = await writeConfigDocBaselineArtifacts({
129-
repoRoot: tempRoot,
130-
rendered,
131-
});
132-
expect(initial.wrote).toBe(true);
133-
134-
const current = await writeConfigDocBaselineArtifacts({
135-
repoRoot: tempRoot,
136-
check: true,
137-
rendered,
138-
});
139-
expect(current.changed).toBe(false);
140-
141-
// Corrupt the hash file to simulate drift
142-
await fs.writeFile(
143-
path.join(tempRoot, "docs/.generated/config-baseline.sha256"),
144-
"0000000000000000000000000000000000000000000000000000000000000000 config-baseline.json\n",
145-
"utf8",
146-
);
147-
148-
const stale = await writeConfigDocBaselineArtifacts({
149-
repoRoot: tempRoot,
150-
check: true,
151-
rendered,
115+
await withTempDir({ prefix: "openclaw-config-doc-baseline-" }, async (tempRoot) => {
116+
const rendered = getSharedRendered();
117+
118+
const initial = await writeConfigDocBaselineArtifacts({
119+
repoRoot: tempRoot,
120+
rendered,
121+
});
122+
expect(initial.wrote).toBe(true);
123+
124+
const current = await writeConfigDocBaselineArtifacts({
125+
repoRoot: tempRoot,
126+
check: true,
127+
rendered,
128+
});
129+
expect(current.changed).toBe(false);
130+
131+
// Corrupt the hash file to simulate drift
132+
await fs.writeFile(
133+
path.join(tempRoot, "docs/.generated/config-baseline.sha256"),
134+
"0000000000000000000000000000000000000000000000000000000000000000 config-baseline.json\n",
135+
"utf8",
136+
);
137+
138+
const stale = await writeConfigDocBaselineArtifacts({
139+
repoRoot: tempRoot,
140+
check: true,
141+
rendered,
142+
});
143+
expect(stale.changed).toBe(true);
144+
expect(stale.wrote).toBe(false);
152145
});
153-
expect(stale.changed).toBe(true);
154-
expect(stale.wrote).toBe(false);
155146
});
156147
});

0 commit comments

Comments
 (0)