From 0a5f3f136e82329d17bfd86b867378c865d6ca17 Mon Sep 17 00:00:00 2001 From: Udaya Tejas Date: Mon, 17 Aug 2026 22:54:04 -0700 Subject: [PATCH] fix(agents): supply the corporate CA to Pi base image builds agents/pi/Dockerfile.base declares ARG NEMOCLAW_CORPORATE_CA_B64 and anchors the decoded certificates before its HTTPS package fetches. agentBaseImageBuildArgs supplied that argument only for Deep Agents Code, so a local Pi base image build received the empty default and produced an image without the configured corporate CA. Supply the argument for Pi, and read the owning test's agent list from the checked-in Dockerfiles so a base image that starts consuming the corporate CA cannot ship without the build argument. Signed-off-by: Udaya Tejas --- src/lib/agent/base-image.test.ts | 76 ++++++++++++++++++++------------ src/lib/agent/base-image.ts | 6 ++- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/lib/agent/base-image.test.ts b/src/lib/agent/base-image.test.ts index 9cc6ed02735..655d2a8aa0e 100644 --- a/src/lib/agent/base-image.test.ts +++ b/src/lib/agent/base-image.test.ts @@ -53,6 +53,23 @@ function makeDifferingImageInspection( : ""; } +const AGENTS_DIR = path.resolve(import.meta.dirname, "../../../agents"); + +function declaresCorporateCaBuildArg(dockerfilePath: string): boolean { + return ( + fs.existsSync(dockerfilePath) && + fs.readFileSync(dockerfilePath, "utf8").includes("ARG NEMOCLAW_CORPORATE_CA_B64") + ); +} + +// Read the agent names from the checked-in Dockerfiles so a base image that +// starts consuming the corporate CA cannot ship without the build argument. +const CORPORATE_CA_BASE_IMAGE_AGENTS = fs + .readdirSync(AGENTS_DIR) + .filter((agentName) => + declaresCorporateCaBuildArg(path.join(AGENTS_DIR, agentName, "Dockerfile.base")), + ); + describe("agent base image provisioning", () => { beforeEach(() => { vi.stubEnv("NEMOCLAW_CORPORATE_CA_ANCHOR_DIRS", ""); @@ -487,35 +504,40 @@ describe("agent base image provisioning", () => { }); }); - it("passes the resolved corporate CA into local agent base image builds (#8119)", () => { - vi.stubEnv("NEMOCLAW_CORPORATE_CA_BUNDLE", writeCa(tmpDir())); - withMockedDocker(({ ensureAgentBaseImage, dockerBuildMock, resolveSandboxBaseImageMock }) => { - resolveSandboxBaseImageMock.mockReturnValue({ - ref: "nemoclaw-dcode-sandbox-base-local:compatible", - digest: null, - source: "local", - glibcVersion: "2.41", - }); + it.each(CORPORATE_CA_BASE_IMAGE_AGENTS)( + "passes the resolved corporate CA into local %s base image builds (#8119)", + (agentName) => { + vi.stubEnv("NEMOCLAW_CORPORATE_CA_BUNDLE", writeCa(tmpDir())); + withMockedDocker(({ ensureAgentBaseImage, dockerBuildMock, resolveSandboxBaseImageMock }) => { + resolveSandboxBaseImageMock.mockReturnValue({ + ref: `nemoclaw-${agentName}-sandbox-base-local:compatible`, + digest: null, + source: "local", + glibcVersion: "2.41", + }); - ensureAgentBaseImage( - makeAgent({ - name: "langchain-deepagents-code", - displayName: "LangChain Deep Agents Code", - expectedVersion: "0.1.34", - dockerfileBasePath: "/test/root/agents/langchain-deepagents-code/Dockerfile.base", - dockerfilePath: "/test/root/agents/langchain-deepagents-code/Dockerfile", - }), - { forceBaseImageRebuild: true }, - ); + ensureAgentBaseImage( + makeAgent({ + name: agentName, + displayName: agentName, + expectedVersion: "0.1.34", + dockerfileBasePath: `/test/root/agents/${agentName}/Dockerfile.base`, + dockerfilePath: `/test/root/agents/${agentName}/Dockerfile`, + }), + { forceBaseImageRebuild: true }, + ); - const options = dockerBuildMock.mock.calls[0]?.[3] as { - buildArgs?: Record; - }; - const encoded = options.buildArgs?.NEMOCLAW_CORPORATE_CA_B64; - expect(encoded).toBeTypeOf("string"); - expect(Buffer.from(encoded ?? "", "base64").toString("utf8")).toContain("BEGIN CERTIFICATE"); - }); - }); + const options = dockerBuildMock.mock.calls[0]?.[3] as { + buildArgs?: Record; + }; + const encoded = options.buildArgs?.NEMOCLAW_CORPORATE_CA_B64; + expect(encoded).toBeTypeOf("string"); + expect(Buffer.from(encoded ?? "", "base64").toString("utf8")).toContain( + "BEGIN CERTIFICATE", + ); + }); + }, + ); it("omits corporate CA build inputs when corporate CA import is disabled (#8119)", () => { vi.stubEnv("NEMOCLAW_CORPORATE_CA_BUNDLE", writeCa(tmpDir())); diff --git a/src/lib/agent/base-image.ts b/src/lib/agent/base-image.ts index e2ce1ca4733..cf3d42701b9 100644 --- a/src/lib/agent/base-image.ts +++ b/src/lib/agent/base-image.ts @@ -63,7 +63,11 @@ function agentBaseImageBuildArgs(agent: AgentDefinition): Record if (agent.name === "nemocua") { return { NEMOCUA_RUNTIME_IMAGE: getCuaSandboxImageRef() }; } - return agent.name === "langchain-deepagents-code" ? corporateCaBuildArgs() : undefined; + // Only these base Dockerfiles declare ARG NEMOCLAW_CORPORATE_CA_B64 and anchor + // the decoded certificates before their HTTPS package fetches (#8119). + return agent.name === "langchain-deepagents-code" || agent.name === "pi" + ? corporateCaBuildArgs() + : undefined; } const HERMES_MCP_RUNTIME_PROBE_OK = "nemoclaw-hermes-mcp-runtime-ok";