fix(secrets): enforce file provider read timeouts

This commit is contained in:
joshavant
2026-02-25 19:08:56 -06:00
committed by Peter Steinberger
parent 67e9554645
commit 86622ebea9
2 changed files with 73 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { resolveSecretRefString, resolveSecretRefValue } from "./resolve.js";
@@ -15,6 +15,7 @@ describe("secret ref resolver", () => {
const cleanupRoots: string[] = [];
afterEach(async () => {
vi.restoreAllMocks();
while (cleanupRoots.length > 0) {
const root = cleanupRoots.pop();
if (!root) {
@@ -280,6 +281,56 @@ describe("secret ref resolver", () => {
expect(value).toBe("raw-token-value");
});
it("times out file provider reads when timeoutMs elapses", async () => {
if (process.platform === "win32") {
return;
}
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-secrets-resolve-timeout-"));
cleanupRoots.push(root);
const filePath = path.join(root, "secrets.json");
await writeSecureFile(
filePath,
JSON.stringify({
providers: {
openai: {
apiKey: "sk-file-value",
},
},
}),
);
const originalReadFile = fs.readFile.bind(fs);
vi.spyOn(fs, "readFile").mockImplementation(((
targetPath: Parameters<typeof fs.readFile>[0],
options?: Parameters<typeof fs.readFile>[1],
) => {
if (typeof targetPath === "string" && targetPath === filePath) {
return new Promise<Buffer>(() => {});
}
return originalReadFile(targetPath, options);
}) as typeof fs.readFile);
await expect(
resolveSecretRefString(
{ source: "file", provider: "filemain", id: "/providers/openai/apiKey" },
{
config: {
secrets: {
providers: {
filemain: {
source: "file",
path: filePath,
mode: "jsonPointer",
timeoutMs: 5,
},
},
},
},
},
),
).rejects.toThrow('File provider "filemain" timed out');
});
it("rejects misconfigured provider source mismatches", async () => {
await expect(
resolveSecretRefValue(