Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
dist
coverage
*.db
*.db-shm
*.db-wal
.git
.env

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Ignore all environment-file variants.

.env.* files can contain secrets. COPY packages/server packages/server can add a package-local .env.production or .env.local to a build-stage layer. Match the .gitignore rule and preserve only .env.example.

Proposed fix
 .env
+.env.*
+!.env.example
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.env
.env
.env.*
!.env.example
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dockerignore at line 8, Update the .dockerignore environment-file rule to
ignore all .env variants, including package-local files, while preserving
.env.example as the sole allowed environment file; align the pattern with the
existing .gitignore rule.

.tsbuildinfo
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copy to .env and adjust. Never commit a real MINIMAX_API_KEY.

# Provider mode: "mock" (default, deterministic, no key) or "minimax" (real API).
PROVIDER_MODE=mock

# Required only when PROVIDER_MODE=minimax. Real mode refuses to start without
# it and NEVER falls back silently to mock.
# MINIMAX_API_KEY=
# MINIMAX_GROUP_ID=
# MINIMAX_BASE_URL=https://api.minimaxi.com

# Server / data
PORT=3001
DB_PATH=./data/h3-studio.db
SEED_SAMPLES=true

# Polling (in-process, single instance)
POLL_INTERVAL_MS=2000
POLL_MAX_ATTEMPTS=120

# Production single-image client serving (set by Docker; leave unset for dev).
# CLIENT_DIST=/app/packages/client/dist
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ node_modules/
dist/
coverage/
.env
.env.*
!.env.example
*.db
*.db-shm
*.db-wal
.DS_Store
*.log
*.tsbuildinfo
50 changes: 50 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# syntax=docker/dockerfile:1.7

# ---- Build stage: install all deps and build shared, client, and server ----
FROM node:22-bookworm-slim AS build
WORKDIR /app
RUN corepack enable
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json ./
COPY packages/shared/package.json packages/shared/
COPY packages/server/package.json packages/server/
COPY packages/client/package.json packages/client/
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile

# Copy sources and build (topological order: shared -> server/client).
COPY packages/shared packages/shared
COPY packages/server packages/server
COPY packages/client packages/client
RUN pnpm -r run build

# ---- Runtime stage: production deps + built artifacts only ----
FROM node:22-bookworm-slim AS runtime
WORKDIR /app
RUN corepack enable

# Install only production dependencies for the workspace.
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json ./
COPY packages/shared/package.json packages/shared/
COPY packages/server/package.json packages/server/
COPY packages/client/package.json packages/client/
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --prod --frozen-lockfile

# Overlay the built artifacts (sources are not needed at runtime).
COPY --from=build /app/packages/shared/dist ./packages/shared/dist
COPY --from=build /app/packages/server/dist ./packages/server/dist
COPY --from=build /app/packages/client/dist ./packages/client/dist

ENV NODE_ENV=production \
PORT=3001 \
DB_PATH=/data/h3-studio.db \
SEED_SAMPLES=true \
PROVIDER_MODE=mock \
CLIENT_DIST=/app/packages/client/dist \
# node:sqlite is experimental in Node 22.
NODE_OPTIONS="--experimental-sqlite --disable-warning=ExperimentalWarning"

EXPOSE 3001
# Migrations run on startup; the in-process poller advances non-terminal jobs.
WORKDIR /app/packages/server
CMD ["node", "dist/server.js"]
Comment on lines +21 to +50

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Run the runtime container as a non-root user.

The runtime stage has no USER instruction. The server therefore runs as root. Create an unprivileged user, grant it ownership of /data, and set USER before CMD.

Proposed fix
 FROM node:22-bookworm-slim AS runtime
 WORKDIR /app
 RUN corepack enable
+RUN groupadd --system --gid 10001 h3 \
+ && useradd --system --uid 10001 --gid h3 --no-create-home h3 \
+ && mkdir -p /data \
+ && chown h3:h3 /data
 ...
 WORKDIR /app/packages/server
+USER h3
 CMD ["node", "dist/server.js"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM node:22-bookworm-slim AS runtime
WORKDIR /app
RUN corepack enable
# Install only production dependencies for the workspace.
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json ./
COPY packages/shared/package.json packages/shared/
COPY packages/server/package.json packages/server/
COPY packages/client/package.json packages/client/
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --prod --frozen-lockfile
# Overlay the built artifacts (sources are not needed at runtime).
COPY --from=build /app/packages/shared/dist ./packages/shared/dist
COPY --from=build /app/packages/server/dist ./packages/server/dist
COPY --from=build /app/packages/client/dist ./packages/client/dist
ENV NODE_ENV=production \
PORT=3001 \
DB_PATH=/data/h3-studio.db \
SEED_SAMPLES=true \
PROVIDER_MODE=mock \
CLIENT_DIST=/app/packages/client/dist \
# node:sqlite is experimental in Node 22.
NODE_OPTIONS="--experimental-sqlite --disable-warning=ExperimentalWarning"
EXPOSE 3001
# Migrations run on startup; the in-process poller advances non-terminal jobs.
WORKDIR /app/packages/server
CMD ["node", "dist/server.js"]
FROM node:22-bookworm-slim AS runtime
WORKDIR /app
RUN corepack enable
RUN groupadd --system --gid 10001 h3 \
&& useradd --system --uid 10001 --gid h3 --no-create-home h3 \
&& mkdir -p /data \
&& chown h3:h3 /data
# Install only production dependencies for the workspace.
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json ./
COPY packages/shared/package.json packages/shared/
COPY packages/server/package.json packages/server/
COPY packages/client/package.json packages/client/
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --prod --frozen-lockfile
# Overlay the built artifacts (sources are not needed at runtime).
COPY --from=build /app/packages/shared/dist ./packages/shared/dist
COPY --from=build /app/packages/server/dist ./packages/server/dist
COPY --from=build /app/packages/client/dist ./packages/client/dist
ENV NODE_ENV=production \
PORT=3001 \
DB_PATH=/data/h3-studio.db \
SEED_SAMPLES=true \
PROVIDER_MODE=mock \
CLIENT_DIST=/app/packages/client/dist \
# node:sqlite is experimental in Node 22.
NODE_OPTIONS="--experimental-sqlite --disable-warning=ExperimentalWarning"
EXPOSE 3001
# Migrations run on startup; the in-process poller advances non-terminal jobs.
WORKDIR /app/packages/server
USER h3
CMD ["node", "dist/server.js"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 21 - 50, Add an unprivileged runtime user in the
Dockerfile’s runtime stage, grant that user ownership of /data, and set USER
before the existing CMD for the server. Keep the current WORKDIR, environment,
and startup command unchanged.

Source: Linters/SAST tools

Loading