From 1119e9cdf4175a8ff1a364008ab20efdf20566fd Mon Sep 17 00:00:00 2001 From: codingsh Date: Sun, 18 Oct 2026 21:10:45 +0100 Subject: [PATCH] fix(cli): apply extraCACerts on deploy deploy never passed extraCACerts to buildImage, so the generated Containerfile set NODE_EXTRA_CA_CERTS to an empty string, and the CA file was not copied into the image either. Copy the CA file into the build output and pass its in-image path as the NODE_EXTRA_CA_CERTS build arg. Co-Authored-By: Claude Sonnet 5.5 --- .changeset/extra-ca-certs-deploy.md | 5 +++++ packages/cli-v3/src/commands/deploy.ts | 6 +++++- packages/cli-v3/src/config.ts | 7 +++++++ packages/cli-v3/src/deploy/buildImage.test.ts | 15 +++++++++++++++ packages/cli-v3/src/deploy/buildImage.ts | 19 ++++++++++++++++++- 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 .changeset/extra-ca-certs-deploy.md diff --git a/.changeset/extra-ca-certs-deploy.md b/.changeset/extra-ca-certs-deploy.md new file mode 100644 index 00000000000..eb8641510bb --- /dev/null +++ b/.changeset/extra-ca-certs-deploy.md @@ -0,0 +1,5 @@ +--- +"trigger.dev": patch +--- + +Fix `extraCACerts` in `trigger.config.ts` having no effect on deployed tasks. The CA file is now included in the deployed image and `NODE_EXTRA_CA_CERTS` points at it, so self-signed or corporate certificates are trusted at runtime. diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts index ce70f4408df..6118c56c46c 100644 --- a/packages/cli-v3/src/commands/deploy.ts +++ b/packages/cli-v3/src/commands/deploy.ts @@ -50,7 +50,7 @@ import { } from "../cli/common.js"; import { loadConfig } from "../config.js"; import { authenticateForDeploy, userIdForDeploy } from "../deploy/auth.js"; -import { buildImage } from "../deploy/buildImage.js"; +import { buildImage, resolveExtraCACertsImagePath } from "../deploy/buildImage.js"; import { checkLogsForErrors, checkLogsForWarnings, @@ -765,6 +765,10 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) { externalBuildProjectId: deployment.externalBuildData?.projectId, projectId: projectClient.id, projectRef: resolvedConfig.project, + extraCACerts: resolveExtraCACertsImagePath( + resolvedConfig.extraCACerts, + resolvedConfig.workingDir + ), apiUrl: projectClient.client.apiURL, apiKey: projectClient.client.accessToken!, apiClient: projectClient.client, diff --git a/packages/cli-v3/src/config.ts b/packages/cli-v3/src/config.ts index a34138cd4c1..8e43049db63 100644 --- a/packages/cli-v3/src/config.ts +++ b/packages/cli-v3/src/config.ts @@ -301,6 +301,13 @@ async function autoDetectDirs(workingDir: string): Promise { } function validateConfig(config: TriggerConfig, warn = true) { + if (config.extraCACerts) { + // The CA file must be inside the build output so the image can point NODE_EXTRA_CA_CERTS at it + config.build ??= {}; + config.build.extensions ??= []; + config.build.extensions.push(additionalFiles({ files: [config.extraCACerts] })); + } + if (config.additionalFiles && config.additionalFiles.length > 0) { warn && prettyWarning( diff --git a/packages/cli-v3/src/deploy/buildImage.test.ts b/packages/cli-v3/src/deploy/buildImage.test.ts index 061c6013d6c..53d9e577bc2 100644 --- a/packages/cli-v3/src/deploy/buildImage.test.ts +++ b/packages/cli-v3/src/deploy/buildImage.test.ts @@ -10,6 +10,7 @@ import { TOOLCHAIN_PACKAGES, formatCommandForDiagnostics, generateContainerfile, + resolveExtraCACertsImagePath, } from "./buildImage.js"; describe("formatCommandForDiagnostics", () => { @@ -53,6 +54,20 @@ const images: Array<[BuildRuntime, string, string]> = [ ], ]; +describe("resolveExtraCACertsImagePath", () => { + it("returns undefined when no CA file is configured", () => { + expect(resolveExtraCACertsImagePath(undefined, "/project")).toBeUndefined(); + }); + + it("maps a project-relative path into /app", () => { + expect(resolveExtraCACertsImagePath("./certs/ca.crt", "/project")).toBe("/app/certs/ca.crt"); + }); + + it("strips leading parent segments the same way additionalFiles does", () => { + expect(resolveExtraCACertsImagePath("../shared/ca.crt", "/project")).toBe("/app/shared/ca.crt"); + }); +}); + describe("generateContainerfile", () => { it.each(images)("uses the pinned published base images for %s", async (runtime, base, build) => { const containerfile = await generateContainerfile({ diff --git a/packages/cli-v3/src/deploy/buildImage.ts b/packages/cli-v3/src/deploy/buildImage.ts index ac41a18d1d7..a6baaa6bdb6 100644 --- a/packages/cli-v3/src/deploy/buildImage.ts +++ b/packages/cli-v3/src/deploy/buildImage.ts @@ -3,7 +3,7 @@ import { depot } from "@depot/cli"; import { x } from "tinyexec"; import type { BuildManifest, BuildRuntime } from "@trigger.dev/core/v3/schemas"; import { networkInterfaces } from "os"; -import { join } from "path"; +import { join, relative, resolve, sep } from "path"; import { safeReadJSONFile } from "../utilities/fileSystem.js"; import { readFileSync } from "fs"; @@ -55,6 +55,23 @@ export interface BuildImageOptions { deploymentSpinner?: any; // Replace 'any' with the actual type if known } +/** + * Where the CA file ends up inside the image. The build copies it into /app using the same layout + * as additionalFiles (path relative to the project root, with leading `..` segments stripped). + */ +export function resolveExtraCACertsImagePath(extraCACerts: string | undefined, workingDir: string) { + if (!extraCACerts) { + return undefined; + } + + const relativePath = relative(workingDir, resolve(workingDir, extraCACerts)) + .split(sep) + .filter((segment) => segment !== "..") + .join("/"); + + return `/app/${relativePath}`; +} + export async function buildImage(options: BuildImageOptions): Promise { const { isLocalBuild,