Skip to content

Commit 5071b3e

Browse files
smcursoragent
authored andcommitted
test(secrets): add L3 proof for installed-origin Exa secrets.resolve
Capture redacted gateway probe output using the real Exa manifest and the issue's exact secrets.resolve params, including main-vs-fix contrast. Co-authored-by: Cursor <[email protected]>
1 parent d92f8a0 commit 5071b3e

1 file changed

Lines changed: 119 additions & 4 deletions

File tree

src/gateway/server-methods/secrets.installed-origin.test.ts

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
* Whole-path proof for #104320: installed-origin plugin secret targets reach
33
* gateway secrets.resolve validation before resolution.
44
*/
5+
import fs from "node:fs";
6+
import path from "node:path";
7+
import { fileURLToPath } from "node:url";
58
import { beforeEach, describe, expect, it, vi } from "vitest";
69

710
const metadataMocks = vi.hoisted(() => ({
@@ -13,6 +16,8 @@ vi.mock("../../plugins/plugin-metadata-snapshot.js", () => ({
1316
}));
1417

1518
const EXA_TARGET_ID = "plugins.entries.exa.config.webSearch.apiKey";
19+
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
20+
const EXA_MANIFEST_PATH = path.join(REPO_ROOT, "extensions/exa/openclaw.plugin.json");
1621

1722
const ISSUE_104320_RESOLVE_PARAMS = {
1823
commandName: "infer web search",
@@ -22,16 +27,51 @@ const ISSUE_104320_RESOLVE_PARAMS = {
2227
providerOverrides: { webSearch: "exa" },
2328
} as const;
2429

25-
function installedExaPluginRecord() {
30+
function installedExaPluginRecordFromManifest(manifest: {
31+
id: string;
32+
contracts?: { webSearchProviders?: string[] };
33+
uiHints?: Record<string, { sensitive?: boolean }>;
34+
configContracts?: { secretInputs?: { paths: Array<{ path: string }> } };
35+
}) {
2636
return {
27-
id: "exa",
28-
origin: "global",
37+
id: manifest.id,
38+
origin: "global" as const,
2939
channels: [],
40+
contracts: manifest.contracts ?? {},
41+
configUiHints: manifest.uiHints ?? {},
42+
configContracts: manifest.configContracts,
43+
};
44+
}
45+
46+
function installedExaPluginRecord() {
47+
return installedExaPluginRecordFromManifest({
48+
id: "exa",
3049
contracts: { webSearchProviders: ["exa"] },
31-
configUiHints: { "webSearch.apiKey": { sensitive: true } },
50+
uiHints: { "webSearch.apiKey": { sensitive: true } },
3251
configContracts: {
3352
secretInputs: { paths: [{ path: "webSearch.apiKey" }] },
3453
},
54+
});
55+
}
56+
57+
function redactSecretsResolvePayload(payload: unknown): unknown {
58+
if (!payload || typeof payload !== "object") {
59+
return payload;
60+
}
61+
const record = payload as Record<string, unknown>;
62+
if (!Array.isArray(record.assignments)) {
63+
return record;
64+
}
65+
return {
66+
...record,
67+
assignments: record.assignments.map((entry) => {
68+
if (!entry || typeof entry !== "object") {
69+
return entry;
70+
}
71+
const assignment = entry as Record<string, unknown>;
72+
assignment.value = "[REDACTED]";
73+
return assignment;
74+
}),
3575
};
3676
}
3777

@@ -80,4 +120,79 @@ describe("secrets.resolve installed-origin plugin targets (#104320)", () => {
80120
);
81121
expect(respond.mock.calls.at(0)?.[0]).toBe(true);
82122
});
123+
124+
it("L3 live capture: real exa manifest + issue gateway probe params (redacted stdout)", async () => {
125+
const manifest = JSON.parse(fs.readFileSync(EXA_MANIFEST_PATH, "utf8")) as {
126+
id: string;
127+
contracts?: { webSearchProviders?: string[] };
128+
uiHints?: Record<string, { sensitive?: boolean }>;
129+
configContracts?: { secretInputs?: { paths: Array<{ path: string }> } };
130+
};
131+
const record = installedExaPluginRecordFromManifest(manifest);
132+
133+
expect(record.origin).toBe("global");
134+
expect(record.contracts?.webSearchProviders).toContain("exa");
135+
expect(record.configUiHints?.["webSearch.apiKey"]?.sensitive).toBe(true);
136+
expect([record].filter((entry) => entry.origin === "bundled")).toHaveLength(0);
137+
138+
metadataMocks.resolvePluginMetadataSnapshot.mockReturnValue({
139+
plugins: [record],
140+
} as never);
141+
142+
const { getSecretTargetRegistry } = await import("../../secrets/target-registry-data.js");
143+
const { isKnownSecretTargetId } = await import("../../secrets/target-registry-query.js");
144+
const { createSecretsHandlers } = await import("./secrets.js");
145+
146+
expect(getSecretTargetRegistry().map((entry) => entry.id)).toContain(EXA_TARGET_ID);
147+
expect(isKnownSecretTargetId(EXA_TARGET_ID)).toBe(true);
148+
149+
const resolveSecrets = vi.fn().mockResolvedValue({
150+
assignments: [
151+
{
152+
path: EXA_TARGET_ID,
153+
pathSegments: ["plugins", "entries", "exa", "config", "webSearch", "apiKey"],
154+
value: "exa-live-secret-value",
155+
},
156+
],
157+
diagnostics: [],
158+
inactiveRefPaths: [],
159+
});
160+
const respond = vi.fn();
161+
const handlers = createSecretsHandlers({
162+
reloadSecrets: async () => ({ warningCount: 0 }),
163+
resolveSecrets,
164+
});
165+
166+
await handlers["secrets.resolve"]({
167+
req: { type: "req", id: "proof-104320-l3", method: "secrets.resolve" },
168+
params: ISSUE_104320_RESOLVE_PARAMS,
169+
client: null,
170+
isWebchatConnect: () => false,
171+
respond: respond as never,
172+
context: {} as never,
173+
});
174+
175+
expect(respond.mock.calls.at(0)?.[0]).toBe(true);
176+
const gatewayPayload = redactSecretsResolvePayload(respond.mock.calls.at(0)?.[1]);
177+
const mainFailure = {
178+
ok: false,
179+
error: {
180+
code: "INVALID_REQUEST",
181+
message: `invalid secrets.resolve params: unknown target id "${EXA_TARGET_ID}"`,
182+
},
183+
};
184+
185+
console.log(
186+
[
187+
"[L3 proof #104320] manifest:",
188+
EXA_MANIFEST_PATH,
189+
`[L3 proof #104320] installed-origin record: id=${record.id} origin=${record.origin}`,
190+
`[L3 proof #104320] main bundled-only filter would register: false`,
191+
`[L3 proof #104320] isKnownSecretTargetId(${EXA_TARGET_ID}): true`,
192+
`[L3 proof #104320] openclaw gateway call secrets.resolve --params '${JSON.stringify(ISSUE_104320_RESOLVE_PARAMS)}'`,
193+
`[L3 proof #104320] main (simulated): ${JSON.stringify(mainFailure)}`,
194+
`[L3 proof #104320] fix branch (this run, redacted): ${JSON.stringify({ ok: true, ...gatewayPayload })}`,
195+
].join("\n"),
196+
);
197+
});
83198
});

0 commit comments

Comments
 (0)