Skip to content

feat(webapp,cli): let self-hosted instances require deploy base images - #5005

Draft
brentshulman-silkline wants to merge 1 commit into
triggerdotdev:mainfrom
brentshulman-silkline:feat/instance-deploy-base-images
Draft

brentshulman-silkline wants to merge 1 commit into
triggerdotdev:mainfrom
brentshulman-silkline:feat/instance-deploy-base-images

Conversation

@brentshulman-silkline

Copy link
Copy Markdown

Closes #5004

Lets a self-hosted operator require custom base images for every deploy to their instance, such as FIPS-validated or hardened Node images. Cloud never sets the new variables, so Cloud users see no new option. This is the instance-level alternative to the per-project config in #5003.

# webapp
DEPLOY_BASE_IMAGES="node-26=registry.example.com/node-fips:26@sha256:..."
DEPLOY_BUILD_BASE_IMAGES="node-26=registry.example.com/node:26-dev@sha256:..."  # optional

What changes

  • webapp:
    • Two optional env vars, both runtime=image csv in the same style as DEPLOY_REGISTRY_ECR_TAGS.
    • resolveDeployBaseImages() picks the images for the deployment's runtime.
    • POST /api/v1/deployments returns them as baseImages on newly created deployments.
  • @trigger.dev/core:
    • InitializeDeploymentResponseBody.baseImages.
    • BuildManifest.image.{base,buildBase}.
  • CLI:
    • When the response includes baseImages, deploy rewrites the Containerfile with them.
    • generateContainerfile falls back to BASE_IMAGE / BUILD_IMAGE when the images are unset.
    • Nothing changes for instances that don't set the variables.
  • Docs:
    • Env rows in self-hosting/env/webapp.
    • A "Custom base images" section in self-hosting/overview that lists what a base must provide, with a warning that apt-based extensions assume Debian.

Open questions

  • The Containerfile is written during buildWorker, before the deployment exists, so the CLI rewrites it after init. Would you rather move initialization ahead of the build?
  • This PR wires the main deploy path only. Should the --from-bundle / native build server paths honor baseImages too, or are those Cloud-only?
  • When a project has image.instructions, the build stage still runs FROM base plus an apt-get toolchain install, which fails on non-Debian bases. Should buildBase cover that case too?

✅ Checklist

  • I have followed every step in the contributing guide
  • The PR title follows the convention.
  • I ran and tested the code works

Testing

  • packages/cli-v3: vitest run src/deploy src/build (9 files, 128 tests) and typecheck pass. New generateContainerfile tests cover base and build overrides on node and bun, and a base-only override.
  • apps/webapp: the new test/deployBaseImages.test.ts passes (5 tests: runtime selection, missing runtime or entry, malformed csv). typecheck reports no errors in the changed files. Its error count is identical with and without this change on my partial local install.
  • oxfmt is clean on the changed files.

Changelog

Self-hosted instances can require custom base images for deploys, such as FIPS-validated or hardened Node images, with the new DEPLOY_BASE_IMAGES webapp setting.


Screenshots

N/A

💯

Adds DEPLOY_BASE_IMAGES / DEPLOY_BUILD_BASE_IMAGES (runtime=image csv) to the
webapp. The deployment initialize response carries the images for the deploy's
runtime, and the CLI rewrites the Containerfile to build on them.
@changeset-bot

changeset-bot Bot commented Oct 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5d3fb37

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 28 packages
Name Type
@trigger.dev/core Patch
trigger.dev Patch
@trigger.dev/build Patch
@trigger.dev/python Patch
@trigger.dev/redis-worker Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/sdk Patch
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/metrics-pipeline Patch
@trigger.dev/rbac Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/run-store Patch
@internal/schedule-engine Patch
@internal/tracing Patch
@internal/webhook-engine Patch
@internal/webhook-sources Patch
@internal/dashboard-agent Patch
@internal/cache Patch
@trigger.dev/react-hooks Patch
@trigger.dev/rsc Patch
@trigger.dev/billing Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch
@trigger.dev/sso Patch
@internal/testcontainers Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

The webapp now accepts per-runtime deploy and build image settings and returns matching images in the deployment response. The CLI uses returned images when rewriting the Containerfile and retains runtime defaults for image fields that are not configured. The changes also add schema and test coverage, self-hosting documentation, and release notes.

Priority: ⬇️ Low

Merge Risk: 🟡 Moderate · up to 5d3fb

Self-hosted operators who configure custom base images may still get published images in two cases: projects that use image instructions, and bundle-based deploys. That weakens the guarantee regulated self-hosters rely on. The Bun documentation also understates what a custom image must provide. Instances without the new settings are unaffected. Resolve these gaps or explicitly accept them before merging.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 5d3fb

Configured image requirements are not enforced consistently across deployment paths. The normal deployment path honors the runtime base image, but bundle builds and existing-deployment attachment can omit it, and project instructions can override the selected build-stage image. Exposure is limited to authenticated deployers on configured instances; existing environment authorization remains intact.

Retained concerns

  • High · security · inferred: The instance-required runtime image is only enforced by the fresh main CLI deployment path. From-bundle builds use their existing Containerfile without applying baseImages, while explicit existing-deployment attachment obtains no image overrides. Finalization verifies deployment ownership and state, not approved base ancestry. An authenticated deployer can therefore deploy an image outside the configured requirement, including for a runtime that has a mapping.
  • Medium · security · observed: Even in the main deployment path, any nonempty project image.instructions selects FROM base plus an apt-installed toolchain instead of the operator-selected buildBase. The runtime base remains selected, but the approved build-stage image is not required. This branch predates the PR for default images; the new security-relevant mismatch is its precedence over an instance-configured build-image requirement.
Security review details

Security Blast Radius

  • inferred — The policy applies instance-wide by runtime, so inconsistent enforcement can affect multiple projects and environments using configured runtimes. Exercising the identified bypass requires deployment authority in the target environment and control of the build path or bundle; it does not demonstrate additional cross-environment authority.

Security Findings and Attack Paths

  • inferred — An authenticated deployer can supply a bundle Containerfile using another runtime base, initialize a local deployment, and build and finalize without applying the returned requirement. The admission path checks environment ownership, worker presence, deployment state, and digest syntax, but not the configured base-image ancestry.
  • observed — A project-controlled nonempty instructions list bypasses buildBase selection within Containerfile generation. The alternate stage still derives from the selected runtime base, limiting this mismatch to the separately configured build-stage requirement.

Trust Boundaries and Controls

  • observed — Trusted operator configuration is conveyed to a deployer-controlled build host through an optional response field. The main consumer honors its precedence, but the server's finalization boundary does not require evidence that the resulting artifact used those images. Existing environment-scoped authorization remains in place.

Resilience and Maintainability Implications

  • observed — Image policy is not included in the inspected deployment creation record. Legacy POST attachment re-resolves current configuration, whereas explicit CLI attachment retrieves the deployment through GET, whose response omits baseImages. These recovery paths therefore do not share a durable image-policy handoff.

Hardening Proposals

  • proposed — If these settings are mandatory security policy, consider server-owned image requirements tied to deployment identity and verified artifact provenance before admission. Apply the contract consistently to fresh builds, bundles, and attachment, and define whether project instructions are permitted to replace a required build-stage image. Alternatively, explicitly expose the feature as advisory image selection rather than enforcement.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning [#5004] The webapp selects runtime-specific images and returns them for new deployments. The main deploy path rewrites the Containerfile, and the generator retains published images when overrides are … Apply the server-selected baseImages to each supported deploy/build path, including --from-bundle and native builds, or prevent those paths from deploying when they cannot honor the configured images.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 10 files. (3 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: self-hosted instances can configure custom deploy base images for the CLI.
Description check ✅ Passed The description is complete and follows the repository template. It identifies the linked issue, explains the changes, includes the checklist, testing details, changelog, and screenshots section, and …
Out of Scope Changes check ✅ Passed All listed changes support [#5004]: environment settings and runtime selection, response and build schemas, CLI image overrides, tests, and self-hosting documentation. The release note and exported `w…
Full details: Linked Issues check

Explanation

[#5004] The webapp selects runtime-specific images and returns them for new deployments. The main deploy path rewrites the Containerfile, and the generator retains published images when overrides are absent. The docs cover runtime versions, required packages, the node user, glibc, and the Debian assumption. However, the PR states that --from-bundle and native build paths are not wired. The CLI also routes --from-bundle through a separate handler before the main deploy flow. This does not establish the issue’s requirement that the operator’s setting apply to every deploy.

Full details: Docstring Coverage

Explanation

Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 10 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8a8f7cfd-ad56-4ebe-907c-ac14d41a7679
📥 Commits

Reviewing files that changed from the base of the PR and between eb04c31 and 5d3fb37.

📒 Files selected for processing (13)
  • .changeset/instance-deploy-base-images.md
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/routes/api.v1.deployments.ts
  • apps/webapp/app/v3/deployBaseImages.server.ts
  • apps/webapp/test/deployBaseImages.test.ts
  • docs/self-hosting/env/webapp.mdx
  • docs/self-hosting/overview.mdx
  • packages/cli-v3/src/build/buildWorker.ts
  • packages/cli-v3/src/commands/deploy.ts
  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/build.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📜 Review details
🧰 Additional context used
📚 Code guidelines (1)
.cursor/rules/webapp.mdc — auto-discovered
📓 Path-based instructions (1)
Source excerpt: In the webapp, all environment variables are accessed through the `env` export of [env.server.ts](mdc:apps/webapp/app/env.server.ts), instead of directly accessing `process.env`.

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Files:

  • apps/webapp/app/routes/api.v1.deployments.ts
  • apps/webapp/test/deployBaseImages.test.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/v3/deployBaseImages.server.ts
🧠 Learnings (2)
📚 Learning: 2026-06-16T09:19:47.637Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3960
File: apps/webapp/test/prismaInfrastructureErrorCapture.test.ts:0-0
Timestamp: 2026-06-16T09:19:47.637Z
Learning: In this repo’s Vitest setup, `vitest.config.ts` uses `globals: true`, so identifiers like `vi`, `describe`, `it`, and `expect` are available as globals in Vitest test files. During code review, do not flag missing `vi`/`describe`/`it`/`expect` imports as a runtime error or correctness issue when they’re used in `*.test.ts/tsx` or `*.spec.ts/tsx` files. Explicit imports are still preferred for consistency, but they’re not required for runtime behavior.

Applied to files:

  • apps/webapp/test/deployBaseImages.test.ts
📚 Learning: 2026-05-20T17:21:18.543Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3678
File: apps/webapp/app/entry.server.tsx:0-0
Timestamp: 2026-05-20T17:21:18.543Z
Learning: In env.server.ts (Zod env schema), any environment variable you plan to access via the typed `env` export (e.g., `env.SENTRY_DSN`) must be explicitly declared in the schema. For `SENTRY_DSN`, include `SENTRY_DSN: z.string().optional()`; otherwise switching from `process.env.SENTRY_DSN` to `env.SENTRY_DSN` will fail TypeScript typechecking.

Applied to files:

  • apps/webapp/app/env.server.ts
🪛 LanguageTool
docs/self-hosting/overview.mdx

[grammar] ~105-~105: Ensure spelling is correct
Context: ... image, set DEPLOY_BASE_IMAGES on the webapp (and optionally `DEPLOY_BUILD_BASE_IMAG...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

Comment on lines +115 to +117
- `node` (or `bun`) on `PATH` at the runtime's major version
- `busybox`, `ca-certificates`, `dumb-init`, `git` and `openssl`
- a `node` user

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the requirements for a custom Bun base. A Bun image also needs node on PATH: the generated final stage runs dumb-init node. It needs a bun user: the generated build and final stages specify USER bun. An image that provides only the documented bun executable and node user can fail to build or start. State the Node and Bun requirements separately. (docs.docker.com)


warnAboutCanceledDeployments(deployment.canceledDeployments, options.externalId);

if (deployment.baseImages) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Apply the image override to fresh bundle deploys. If a deploy uses --from-bundle, _deployCommand returns before this rewrite. handleFromBundleDeploy then initializes the deployment and builds the supplied bundle without using its baseImages. On an instance with an override, that CLI path does not build from the configured image. Apply the override to the bundle’s Containerfile before buildAndFinalizeFromBundle.

apt-get clean && \\
rm -rf /var/lib/apt/lists/*`
: `FROM ${BUILD_IMAGE[options.runtime]} AS build
: `FROM ${options.image?.buildBase ?? BUILD_IMAGE[options.runtime]} AS build

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Honor buildBase when image instructions are present. If image.instructions is nonempty, the other branch generates FROM base AS build. It never reads the operator’s buildBase, even when DEPLOY_BUILD_BASE_IMAGES matches the runtime. This defeats the configured build-stage image for projects with instructions. Make the instructions path use the configured build base, or reject this combination with a clear error. (docs.docker.com)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: let self-hosted instances require custom deploy base images (FIPS / hardened)

1 participant