Skip to content

feat: add hardened standalone container build - #624

Merged
mergify[bot] merged 1 commit into
mainfrom
feat/618-hardened-docker-build
Jul 11, 2026
Merged

feat: add hardened standalone container build#624
mergify[bot] merged 1 commit into
mainfrom
feat/618-hardened-docker-build

Conversation

@charliecreates

@charliecreates charliecreates Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a standalone tsdown server build for container deployment.
  • Use a two-stage official node:lts-alpine image with a non-root runtime and no application node_modules in the final image.
  • Allowlist the Docker build context and add CI structural smoke checks.
  • Document container build and runtime usage.
  • Add a patch changeset.

Validation

  • npm run build
  • npm run build:standalone
  • node dist/standalone.mjs --version
  • node dist/standalone.mjs --help
  • standalone dependency/import audit
  • npm run check:types
  • npm run check
  • npx vitest run --exclude tests/integration/**
  • npm run check:changeset

A local Docker engine was unavailable, so GitHub Actions performs the Docker build and runtime checks.

Resolves #618

✨ PR Description

Purpose: Convert Docker container build to hardened standalone Node.js bundle without application node_modules directory and run as non-root user.

Main changes:

  • Modified tsdown config to support standalone build mode bundling all dependencies into single CLI entry point
  • Refactored Dockerfile to use multi-stage build with Node.js Alpine base and non-root node user execution
  • Updated .dockerignore to whitelist minimal build inputs and deny all others for reduced build context

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
💡 Tip: You can customize your AI Description using Guidelines Learn how

@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.94%. Comparing base (0f03660) to head (b5dcbd7).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #624   +/-   ##
=======================================
  Coverage   92.94%   92.94%           
=======================================
  Files          35       35           
  Lines        1559     1559           
  Branches      392      392           
=======================================
  Hits         1449     1449           
  Misses         48       48           
  Partials       62       62           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mergify

mergify Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Queued — the merge queue status continues in this comment ↓.

@gitstream-cm gitstream-cm 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.

✨ PR Review

The PR introduces a well-structured two-stage standalone container build with a sensible .dockerignore allowlist and CI smoke checks. Two concrete issues were identified: a floating base-image tag that breaks reproducibility and risks a future runtime/compile-target mismatch, and a versioned changeset used for what the project's own rules classify as an internal-only change.

2 issues detected:

🧹 Maintainability - `node:lts-alpine` is a mutable tag; future LTS transitions will silently swap the runtime engine and break the node24 compile target.

Details: Both FROM node:lts-alpine stages use a mutable floating tag. When the Node.js LTS pointer moves to a new major (e.g., Node 26), both the build toolchain and the runtime will silently change. This also creates a hard mismatch with the target: "node24" value hardcoded in tsdown.config.ts: the standalone bundle is compiled for Node 24 APIs/syntax but will eventually be executed on a different engine version without any warning.

File: Dockerfile (3-14)

🧹 Maintainability - A `patch` version bump is emitted for a purely internal Docker/CI change, violating the project's own changeset guidelines.

Details: The project's own contribution rules state "use a versioned changeset only for user-facing, runtime-visible changes; use npx changeset --empty for docs, CI, tests, refactors, and other internal-only changes." Adding a Dockerfile, .dockerignore, and CI workflow is a build/ops change with no effect on the published npm package's runtime behaviour, so a versioned patch bump is incorrect here.

File: .changeset/calm-taxis-build.md (1-5)

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
💡 Tip: You can customize your AI Review using Guidelines Learn how

@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Unit Test Results

  1 files   32 suites   2s ⏱️
513 tests 513 ✅ 0 💤 0 ❌
517 runs  517 ✅ 0 💤 0 ❌

Results for commit b5dcbd7.

♻️ This comment has been updated with latest results.

@charliecreates
charliecreates Bot force-pushed the feat/618-hardened-docker-build branch from 40b98a7 to b5dcbd7 Compare July 11, 2026 06:07

@gitstream-cm gitstream-cm 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.

✨ PR Review

The PR introduces a clean two-stage standalone Docker build. The allowlist .dockerignore, CI smoke checks, and bundling approach are well-structured. Two previously flagged issues (mutable lts-alpine tag and incorrect versioned changeset for a CI/ops change) remain unresolved and are not re-raised here. One new concrete bug was found in the tsdown configuration.

1 issues detected:

🐞 Bug - `clean: true` deletes the entire shared `dist/` folder before each build, so whichever build runs second erases the other's output.

Details: Both npm run build and npm run build:standalone use outDir: "dist" with clean: true. Running build:standalone wipes the entire dist/ directory and writes only standalone.mjs; a subsequent npm run build (or prepack) then wipes standalone.mjs and writes the library/CLI artefacts. The two build modes cannot coexist and will silently corrupt each other in any workflow that invokes both (e.g., a developer iterating locally, or a CI job that runs prepack after the Docker build step in the same workspace).

File: tsdown.config.ts (65-83)

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
💡 Tip: You can customize your AI Review using Guidelines Learn how

@mergify

mergify Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 2 minutes 47 seconds in the queue, including 1 minute 20 seconds running CI.

Required conditions to merge
  • check-success = "Build and test (Node 24.x)"
  • check-success = "Build and test (Node 26.x)"

mergify Bot added a commit that referenced this pull request Jul 11, 2026
@mergify
mergify Bot merged commit f68b258 into main Jul 11, 2026
27 checks passed
@mergify
mergify Bot deleted the feat/618-hardened-docker-build branch July 11, 2026 10:54
mergify Bot added a commit that referenced this pull request Jul 11, 2026
@mergify mergify Bot removed the queued label Jul 11, 2026
@github-actions github-actions Bot mentioned this pull request Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

queue Add to Mergify merge queue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Containerize MCP server using a hardened multi-stage Docker build with tsdown

2 participants