mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:30:42 +00:00
fix(gateway): log secrets handler error details
This commit is contained in:
@@ -30,6 +30,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Gateway/secrets: include the caught error message in `secrets.reload` and `secrets.resolve` warning logs while keeping RPC errors generic, so operators can diagnose reload and permission failures. Thanks @davidangularme.
|
||||
- fix(infra): block workspace state-directory env override [AI]. (#75940) Thanks @pgondhi987.
|
||||
- MCP/OpenAI: normalize parameter-free tool schemas whose top-level object `properties` is missing, null, or invalid before sending tools to OpenAI, so MCP tools without params stay usable. Fixes #75362. Thanks @tolkonepiu and @SymbolStar.
|
||||
- TTS: honor explicit short `[[tts:text]]...[[/tts:text]]` blocks while keeping untagged short auto-TTS suppressed, so tagged voice replies are synthesized instead of being dropped as empty voice-only payloads. Fixes #73758. Thanks @yfge.
|
||||
|
||||
@@ -50,6 +50,7 @@ describe("secrets handlers", () => {
|
||||
diagnostics: string[];
|
||||
inactiveRefPaths: string[];
|
||||
}>;
|
||||
log?: { warn?: (message: string) => void };
|
||||
}) {
|
||||
const reloadSecrets = overrides?.reloadSecrets ?? (async () => ({ warningCount: 0 }));
|
||||
const resolveSecrets =
|
||||
@@ -62,6 +63,7 @@ describe("secrets handlers", () => {
|
||||
return createSecretsHandlers({
|
||||
reloadSecrets,
|
||||
resolveSecrets,
|
||||
log: overrides?.log,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -75,8 +77,10 @@ describe("secrets handlers", () => {
|
||||
});
|
||||
|
||||
it("returns unavailable when reload fails", async () => {
|
||||
const warn = vi.fn();
|
||||
const handlers = createHandlers({
|
||||
reloadSecrets: vi.fn().mockRejectedValue(new Error("reload failed")),
|
||||
reloadSecrets: vi.fn().mockRejectedValue(new Error("disk full")),
|
||||
log: { warn },
|
||||
});
|
||||
const respond = vi.fn();
|
||||
await invokeSecretsReload({ handlers, respond });
|
||||
@@ -88,6 +92,7 @@ describe("secrets handlers", () => {
|
||||
message: "secrets.reload failed",
|
||||
}),
|
||||
);
|
||||
expect(warn).toHaveBeenCalledWith(expect.stringContaining("disk full"));
|
||||
});
|
||||
|
||||
it("resolves requested command secret assignments from the active snapshot", async () => {
|
||||
@@ -189,12 +194,13 @@ describe("secrets handlers", () => {
|
||||
});
|
||||
|
||||
it("returns unavailable when secrets.resolve handler returns an invalid payload shape", async () => {
|
||||
const warn = vi.fn();
|
||||
const resolveSecrets = vi.fn().mockResolvedValue({
|
||||
assignments: [{ path: TALK_TEST_PROVIDER_API_KEY_PATH, pathSegments: [""], value: "sk" }],
|
||||
diagnostics: [],
|
||||
inactiveRefPaths: [],
|
||||
});
|
||||
const handlers = createHandlers({ resolveSecrets });
|
||||
const handlers = createHandlers({ resolveSecrets, log: { warn } });
|
||||
const respond = vi.fn();
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
@@ -210,5 +216,32 @@ describe("secrets handlers", () => {
|
||||
message: "secrets.resolve failed",
|
||||
}),
|
||||
);
|
||||
expect(warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("secrets.resolve returned invalid payload."),
|
||||
);
|
||||
});
|
||||
|
||||
it("logs error details when secrets.resolve throws", async () => {
|
||||
const warn = vi.fn();
|
||||
const handlers = createHandlers({
|
||||
resolveSecrets: vi.fn().mockRejectedValue(new Error("EACCES: permission denied")),
|
||||
log: { warn },
|
||||
});
|
||||
const respond = vi.fn();
|
||||
await invokeSecretsResolve({
|
||||
handlers,
|
||||
respond,
|
||||
commandName: "memory status",
|
||||
targetIds: ["talk.providers.*.apiKey"],
|
||||
});
|
||||
expect(respond).toHaveBeenCalledWith(
|
||||
false,
|
||||
undefined,
|
||||
expect.objectContaining({
|
||||
code: "UNAVAILABLE",
|
||||
message: "secrets.resolve failed",
|
||||
}),
|
||||
);
|
||||
expect(warn).toHaveBeenCalledWith(expect.stringContaining("EACCES: permission denied"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
} from "../protocol/index.js";
|
||||
import type { GatewayRequestHandlers } from "./types.js";
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function invalidSecretsResolveField(
|
||||
errors: ErrorObject[] | null | undefined,
|
||||
): "commandName" | "targetIds" {
|
||||
@@ -43,8 +47,8 @@ export function createSecretsHandlers(params: {
|
||||
try {
|
||||
const result = await params.reloadSecrets();
|
||||
respond(true, { ok: true, warningCount: result.warningCount });
|
||||
} catch {
|
||||
params.log?.warn?.("secrets.reload failed");
|
||||
} catch (error) {
|
||||
params.log?.warn?.(`secrets.reload failed: ${errorMessage(error)}`);
|
||||
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "secrets.reload failed"));
|
||||
}
|
||||
},
|
||||
@@ -100,8 +104,8 @@ export function createSecretsHandlers(params: {
|
||||
throw new Error("secrets.resolve returned invalid payload.");
|
||||
}
|
||||
respond(true, payload);
|
||||
} catch {
|
||||
params.log?.warn?.("secrets.resolve failed");
|
||||
} catch (error) {
|
||||
params.log?.warn?.(`secrets.resolve failed: ${errorMessage(error)}`);
|
||||
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "secrets.resolve failed"));
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user