fix: handle Linux nvm CA env before startup (#51146) (thanks @GodsBoy)

This commit is contained in:
Peter Steinberger
2026-03-21 10:47:29 -07:00
parent d6367c2c55
commit 40f5305cd2
11 changed files with 544 additions and 56 deletions

View File

@@ -1,7 +1,8 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { captureFullEnv } from "../../test-utils/env.js";
import type { DaemonActionResponse } from "./response.js";
import { captureFullEnv } from "../../test-utils/env.js";
const resolveAutoNodeExtraCaCertsMock = vi.hoisted(() => vi.fn());
const loadConfigMock = vi.hoisted(() => vi.fn());
const readConfigFileSnapshotMock = vi.hoisted(() => vi.fn());
const resolveGatewayPortMock = vi.hoisted(() => vi.fn(() => 18789));
@@ -50,6 +51,10 @@ const service = vi.hoisted(() => ({
readRuntime: vi.fn(async () => ({ status: "stopped" as const })),
}));
vi.mock("../../bootstrap/node-extra-ca-certs.js", () => ({
resolveAutoNodeExtraCaCerts: resolveAutoNodeExtraCaCertsMock,
}));
vi.mock("../../config/config.js", () => ({
loadConfig: loadConfigMock,
readBestEffortConfig: loadConfigMock,
@@ -151,6 +156,7 @@ const envSnapshot = captureFullEnv();
describe("runDaemonInstall", () => {
beforeEach(() => {
loadConfigMock.mockReset();
resolveAutoNodeExtraCaCertsMock.mockReset();
readConfigFileSnapshotMock.mockReset();
resolveGatewayPortMock.mockClear();
writeConfigFileMock.mockReset();
@@ -191,6 +197,8 @@ describe("runDaemonInstall", () => {
isGatewayDaemonRuntimeMock.mockReturnValue(true);
installDaemonServiceAndEmitMock.mockResolvedValue(undefined);
service.isLoaded.mockResolvedValue(false);
service.readCommand.mockResolvedValue(null);
resolveAutoNodeExtraCaCertsMock.mockReturnValue(undefined);
delete process.env.OPENCLAW_GATEWAY_TOKEN;
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
});
@@ -289,4 +297,33 @@ describe("runDaemonInstall", () => {
expect(actionState.failed[0]?.message).toContain("read-only file system");
expect(installDaemonServiceAndEmitMock).not.toHaveBeenCalled();
});
it("returns already-installed when the service already has the expected TLS env", async () => {
service.isLoaded.mockResolvedValue(true);
resolveAutoNodeExtraCaCertsMock.mockReturnValue("/etc/ssl/certs/ca-certificates.crt");
service.readCommand.mockResolvedValue({
programArguments: ["openclaw", "gateway", "run"],
environment: {
NODE_EXTRA_CA_CERTS: "/etc/ssl/certs/ca-certificates.crt",
},
} as never);
await runDaemonInstall({ json: true });
expect(installDaemonServiceAndEmitMock).not.toHaveBeenCalled();
expect(actionState.emitted.at(-1)).toMatchObject({ result: "already-installed" });
});
it("reinstalls when an existing service is missing the nvm TLS CA bundle", async () => {
service.isLoaded.mockResolvedValue(true);
resolveAutoNodeExtraCaCertsMock.mockReturnValue("/etc/ssl/certs/ca-certificates.crt");
service.readCommand.mockResolvedValue({
programArguments: ["openclaw", "gateway", "run"],
environment: {},
} as never);
await runDaemonInstall({ json: true });
expect(installDaemonServiceAndEmitMock).toHaveBeenCalledTimes(1);
});
});