Download src/proxy-capture/ca.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 7.66 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/proxy-capture/ca.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/proxy-capture/ca.test.ts
-
curl -L -o ca.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/proxy-capture/ca.test.ts
7.66 kB
| // Proxy capture CA tests cover bounded certificate generation. | |
| import fs from "node:fs"; | |
| import path from "node:path"; | |
| import { afterEach, describe, expect, it, vi } from "vitest"; | |
| import { createTrackedTempDirs } from "../test-utils/tracked-temp-dirs.js"; | |
| const { resolveSystemBinMock, runExecMock } = vi.hoisted(() => ({ | |
| resolveSystemBinMock: vi.fn(() => "/usr/bin/openssl"), | |
| runExecMock: vi.fn(), | |
| })); | |
| vi.mock("node:crypto", async (importOriginal) => { | |
| const actual = await importOriginal<typeof import("node:crypto")>(); | |
| const parseMarker = (value: Buffer, prefix: string): string => { | |
| const text = value.toString("utf8"); | |
| if (!text.startsWith(prefix)) { | |
| throw new Error("invalid certificate material"); | |
| } | |
| return text.slice(prefix.length); | |
| }; | |
| const cryptoMock = { ...actual } as typeof actual; | |
| Object.defineProperties(cryptoMock, { | |
| createPrivateKey: { | |
| value: (value: Buffer) => ({ marker: parseMarker(value, "ca-material-marker:") }), | |
| }, | |
| X509Certificate: { | |
| value: class { | |
| readonly ca: boolean; | |
| readonly marker: string; | |
| constructor(value: Buffer) { | |
| this.marker = parseMarker(value, "ca-cert-marker:"); | |
| this.ca = this.marker !== "not-ca"; | |
| } | |
| checkPrivateKey(key: { marker?: string }): boolean { | |
| return key.marker === this.marker; | |
| } | |
| }, | |
| }, | |
| }); | |
| return cryptoMock; | |
| }); | |
| vi.mock("../infra/resolve-system-bin.js", () => ({ resolveSystemBin: resolveSystemBinMock })); | |
| vi.mock("../process/exec.js", async (importOriginal) => ({ | |
| ...(await importOriginal<typeof import("../process/exec.js")>()), | |
| runExec: runExecMock, | |
| })); | |
| import { ensureDebugProxyCa } from "./ca.js"; | |
| const tempDirs = createTrackedTempDirs(); | |
| function outputPath(args: string[], flag: "-config" | "-keyout" | "-out"): string { | |
| const index = args.indexOf(flag); | |
| const value = args[index + 1]; | |
| if (!value) { | |
| throw new Error(`missing ${flag} output path`); | |
| } | |
| return value; | |
| } | |
| function writeGeneratedPair(args: string[], marker: string): void { | |
| fs.writeFileSync(outputPath(args, "-out"), `ca-cert-marker:${marker}`); | |
| fs.writeFileSync(outputPath(args, "-keyout"), `ca-material-marker:${marker}`); | |
| } | |
| async function makeCertPaths() { | |
| const certDir = await tempDirs.make("openclaw-proxy-ca-"); | |
| return { | |
| certDir, | |
| certPath: path.join(certDir, "root-ca.pem"), | |
| keyPath: path.join(certDir, "root-ca-key.pem"), | |
| }; | |
| } | |
| function generatePair(marker: string): void { | |
| runExecMock.mockImplementationOnce(async (_command: string, args: string[]) => { | |
| writeGeneratedPair(args, marker); | |
| }); | |
| } | |
| afterEach(async () => { | |
| vi.restoreAllMocks(); | |
| runExecMock.mockReset(); | |
| await tempDirs.cleanup(); | |
| }); | |
| describe("ensureDebugProxyCa", () => { | |
| it("regenerates after partial output timeout without reusing stale final files", async () => { | |
| const { certDir, certPath, keyPath } = await makeCertPaths(); | |
| fs.writeFileSync(certPath, "stale partial cert"); | |
| fs.writeFileSync(keyPath, "stale partial key"); | |
| let generatedConfig = ""; | |
| runExecMock | |
| .mockImplementationOnce(async (_command: string, args: string[]) => { | |
| generatedConfig = fs.readFileSync(outputPath(args, "-config"), "utf8"); | |
| fs.writeFileSync(outputPath(args, "-out"), "partial cert"); | |
| fs.writeFileSync(outputPath(args, "-keyout"), "partial key"); | |
| throw new Error("openssl timed out"); | |
| }) | |
| .mockImplementationOnce(async (_command: string, args: string[]) => { | |
| writeGeneratedPair(args, "retry"); | |
| }); | |
| await expect(ensureDebugProxyCa(certDir)).rejects.toThrow("openssl timed out"); | |
| expect(fs.readFileSync(certPath, "utf8")).toBe("stale partial cert"); | |
| expect(fs.readFileSync(keyPath, "utf8")).toBe("stale partial key"); | |
| expect(fs.readdirSync(certDir).toSorted()).toEqual(["root-ca-key.pem", "root-ca.pem"]); | |
| await expect( | |
| Promise.all([ensureDebugProxyCa(certDir), ensureDebugProxyCa(certDir)]), | |
| ).resolves.toEqual([ | |
| { certPath, keyPath }, | |
| { certPath, keyPath }, | |
| ]); | |
| expect(runExecMock).toHaveBeenCalledTimes(2); | |
| const [command, args, options] = runExecMock.mock.calls[0] as [string, string[], object]; | |
| expect(command).toBe("/usr/bin/openssl"); | |
| expect(args).toEqual(expect.arrayContaining(["req", "-extensions", "v3_ca", "-x509"])); | |
| expect(path.dirname(outputPath(args, "-config"))).toBe(path.dirname(outputPath(args, "-out"))); | |
| expect(path.dirname(outputPath(args, "-out")).startsWith(`${certDir}${path.sep}`)).toBe(true); | |
| expect(options).toEqual({ logOutput: false, timeoutMs: 30_000 }); | |
| expect(generatedConfig).toContain("CN = OpenClaw Debug Proxy"); | |
| expect(generatedConfig).toContain("basicConstraints = critical, CA:TRUE"); | |
| expect(generatedConfig).toContain("keyUsage = critical, keyCertSign, cRLSign"); | |
| }); | |
| it("rejects matching certificate material that is not a CA", async () => { | |
| const { certDir } = await makeCertPaths(); | |
| generatePair("not-ca"); | |
| await expect(ensureDebugProxyCa(certDir)).rejects.toThrow( | |
| "openssl generated invalid debug proxy certificate material", | |
| ); | |
| expect(fs.readdirSync(certDir)).toEqual([]); | |
| }); | |
| it("waits for a live lock owner before generating", async () => { | |
| const { certDir, certPath, keyPath } = await makeCertPaths(); | |
| const lockPath = `${keyPath}.lock`; | |
| fs.writeFileSync(lockPath, JSON.stringify({ pid: process.pid, createdAt: new Date() })); | |
| generatePair("live-owner-retry"); | |
| const releaseOwner = setTimeout(() => fs.rmSync(lockPath, { force: true }), 150); | |
| try { | |
| await expect(ensureDebugProxyCa(certDir)).resolves.toEqual({ certPath, keyPath }); | |
| } finally { | |
| clearTimeout(releaseOwner); | |
| } | |
| expect(runExecMock).toHaveBeenCalledTimes(1); | |
| }); | |
| it("recovers when publication is interrupted between the two renames", async () => { | |
| const { certDir, certPath, keyPath } = await makeCertPaths(); | |
| fs.writeFileSync(certPath, "stale cert"); | |
| fs.writeFileSync(keyPath, "stale key"); | |
| runExecMock | |
| .mockImplementationOnce(async (_command: string, args: string[]) => { | |
| writeGeneratedPair(args, "failed-publication"); | |
| }) | |
| .mockImplementationOnce(async (_command: string, args: string[]) => { | |
| writeGeneratedPair(args, "retry-after-publication"); | |
| }); | |
| const renameSync = fs.renameSync.bind(fs); | |
| let rejectedPublishedCert = false; | |
| const renameSpy = vi.spyOn(fs, "renameSync").mockImplementation((source, destination) => { | |
| const sourcePath = source.toString(); | |
| if ( | |
| !rejectedPublishedCert && | |
| destination.toString() === certPath && | |
| sourcePath.includes(`${path.sep}.root-ca-`) | |
| ) { | |
| rejectedPublishedCert = true; | |
| throw Object.assign(new Error("certificate publication failed"), { code: "EACCES" }); | |
| } | |
| renameSync(source, destination); | |
| }); | |
| await expect(ensureDebugProxyCa(certDir)).rejects.toThrow("certificate publication failed"); | |
| expect(fs.readFileSync(certPath, "utf8")).toBe("stale cert"); | |
| expect(fs.readFileSync(keyPath, "utf8")).toBe("ca-material-marker:failed-publication"); | |
| expect(fs.readdirSync(certDir).toSorted()).toEqual(["root-ca-key.pem", "root-ca.pem"]); | |
| renameSpy.mockRestore(); | |
| await expect(ensureDebugProxyCa(certDir)).resolves.toEqual({ certPath, keyPath }); | |
| expect(fs.readFileSync(certPath, "utf8")).toBe("ca-cert-marker:retry-after-publication"); | |
| expect(fs.readFileSync(keyPath, "utf8")).toBe("ca-material-marker:retry-after-publication"); | |
| expect(runExecMock).toHaveBeenCalledTimes(2); | |
| }); | |
| }); | |