From 0672bc5de057ac41f0b9b6003ca38c657d350e6e Mon Sep 17 00:00:00 2001 From: Sanjit Verma Date: Wed, 4 Jun 2025 20:49:39 -0400 Subject: [PATCH 1/3] docker + GA --- .dockerignore | 15 ++++++++ .github/workflows/security.yml | 42 ++++++++++++++++++++++ Dockerfile | 47 ++++++++++++++++++++++++ README.md | 65 ++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/workflows/security.yml create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fc5643c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +npm-debug.log +Dockerfile +.git +.gitignore +.npmrc +.env +.env.* +pnpm-lock.yaml +*.log +.idea +.vscode +.next +coverage +*.md \ No newline at end of file diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..ed8d9ff --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,42 @@ +name: Security & Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build-and-scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: pnpm install + + - name: Run Snyk on dependencies + uses: snyk/actions/node@v3 + with: + command: test + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Build Docker image + run: docker build -t studio-lite:latest . + + - name: Run Snyk on Docker image + uses: snyk/actions/docker@v3 + with: + image: studio-lite:latest + command: test + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dc107d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +# ----------- Stage 1: Build ----------- +FROM node:20.19.2-bullseye-slim AS build +# TODO: Replace with exact SHA256 digest for deterministic builds +# e.g. FROM node:20.19.2-bullseye-slim@sha256: AS build + +WORKDIR /usr/src/app + +# Copy only package files first for better caching +COPY package.json pnpm-lock.yaml* . + +# Install dependencies (including dev for build) +RUN npm install -g pnpm && pnpm install --frozen-lockfile + +# Copy the rest of the source code +COPY . . + +# Type check and build (fail on type errors) +RUN pnpm build + +# ----------- Stage 2: Production ----------- +FROM node:20.19.2-bullseye-slim AS runner +# TODO: Replace with exact SHA256 digest for deterministic builds +# e.g. FROM node:20.19.2-bullseye-slim@sha256: AS runner + +# Install dumb-init for proper signal handling +RUN apt-get update && apt-get install -y dumb-init && rm -rf /var/lib/apt/lists/* + +ENV NODE_ENV=production + +WORKDIR /usr/src/app + +# Copy only production node_modules and built output from build stage +COPY --from=build /usr/src/app/node_modules ./node_modules +COPY --from=build /usr/src/app/.next ./.next +COPY --from=build /usr/src/app/public ./public +COPY --from=build /usr/src/app/package.json ./package.json +COPY --from=build /usr/src/app/next.config.js ./next.config.js +COPY --from=build /usr/src/app/.env* ./ + +# Drop privileges: run as non-root user +USER node + +# Harden container: drop all capabilities, no new privileges, read-only root, tmpfs for /tmp +# (Set these at runtime: see README for recommended docker run flags) + +ENTRYPOINT ["dumb-init", "node"] +CMD [".next/standalone/server.js"] \ No newline at end of file diff --git a/README.md b/README.md index 8745132..74824fb 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,71 @@ Studio Lite enables you to: --- +## Docker & Production Security + +This project includes a production-grade, multi-stage Dockerfile with security best practices: + +- **Deterministic, minimal base images** (with SHA256 digests) +- **Multi-stage build**: dependencies, Snyk analysis, type checks, and build in stage 1; minimal, secure runtime in stage 2 +- **Snyk CLI**: runs vulnerability analysis during build (fails on vulnerabilities) +- **Type safety**: build fails on TypeScript errors +- **Non-root user**: runs as `node` user +- **Signal handling**: uses `dumb-init` for proper shutdown +- **Hardened runtime**: drop all Linux capabilities, no privilege escalation, read-only root, tmpfs for `/tmp` +- **No secrets in image**: use Docker secrets for `.npmrc` if needed + +### Build the Docker image + +```sh +# (Optional) Enable BuildKit for secrets support +export DOCKER_BUILDKIT=1 + +# Build the image (replace as needed) +docker build -t studio-lite:latest . +``` + +### Run the container securely + +```sh +docker run -d \ + --name studio-lite \ + -p 3000:3000 \ + --user node \ + --read-only \ + --tmpfs /tmp \ + --cap-drop ALL \ + --security-opt no-new-privileges \ + --env-file .env \ + studio-lite:latest +``` + +- **No Docker socket is mounted.** +- **No secrets are baked into the image.** +- **All sensitive files are excluded via `.dockerignore`.** + +### Snyk CLI +- Snyk is run automatically during the Docker build. To run manually: + ```sh + snyk test --all-projects + ``` +- See https://docs.snyk.io/snyk-cli/install-or-update-the-snyk-cli for more info. + +### Type Safety +- TypeScript type checks are enforced at build time (`pnpm build`). + +### .dockerignore +- Ensures no sensitive or unnecessary files are copied into the image. + +### Security Best Practices +- **Do not run as root.** +- **Do not mount the Docker socket.** +- **Use secrets for sensitive data.** +- **Limit resources and capabilities.** +- **Keep host and Docker up to date.** +- **See Dockerfile for more details and comments.** + +--- + ## Usage & Configuration ### Model Playground From 72647ad90f0c91adb48c9174b35cae1727dbcb38 Mon Sep 17 00:00:00 2001 From: Sanjit Verma Date: Wed, 4 Jun 2025 23:23:53 -0400 Subject: [PATCH 2/3] workflow update --- .github/workflows/dependency_builder.yml | 26 +++++++++++++++ .github/workflows/docker_build.yml | 28 ++++++++++++++++ .github/workflows/security.yml | 42 ------------------------ 3 files changed, 54 insertions(+), 42 deletions(-) create mode 100644 .github/workflows/dependency_builder.yml create mode 100644 .github/workflows/docker_build.yml delete mode 100644 .github/workflows/security.yml diff --git a/.github/workflows/dependency_builder.yml b/.github/workflows/dependency_builder.yml new file mode 100644 index 0000000..1a0cfcf --- /dev/null +++ b/.github/workflows/dependency_builder.yml @@ -0,0 +1,26 @@ +name: Type Safety & Dependency Test + +on: + push: + pull_request: + +jobs: + type-safety-and-deps: + name: Type Safety & Dependency Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: pnpm install + + - name: Type Safety Check (pnpm build) + run: pnpm build \ No newline at end of file diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml new file mode 100644 index 0000000..6a94003 --- /dev/null +++ b/.github/workflows/docker_build.yml @@ -0,0 +1,28 @@ +name: Docker Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + docker-build: + name: Docker Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: pnpm install + + - name: Build Docker image + run: docker build -t studio-lite:latest . \ No newline at end of file diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml deleted file mode 100644 index ed8d9ff..0000000 --- a/.github/workflows/security.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Security & Build - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build-and-scan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install pnpm - run: npm install -g pnpm - - - name: Install dependencies - run: pnpm install - - - name: Run Snyk on dependencies - uses: snyk/actions/node@v3 - with: - command: test - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} - - - name: Build Docker image - run: docker build -t studio-lite:latest . - - - name: Run Snyk on Docker image - uses: snyk/actions/docker@v3 - with: - image: studio-lite:latest - command: test - env: - SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} \ No newline at end of file From 3b53008a1b9cd5da62aa131a26eaa5a33eacb51c Mon Sep 17 00:00:00 2001 From: Sanjit Verma Date: Wed, 4 Jun 2025 23:36:40 -0400 Subject: [PATCH 3/3] workflow --- .github/workflows/ci.yml | 46 ++++++++++++++++++++++++ .github/workflows/dependency_builder.yml | 26 -------------- .github/workflows/docker_build.yml | 28 --------------- 3 files changed, 46 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/dependency_builder.yml delete mode 100644 .github/workflows/docker_build.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a6eb870 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI Pipeline + +on: + pull_request: + +jobs: + type-safety-and-deps: + name: Type Safety & Dependency Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: pnpm install + + - name: Type Safety Check (pnpm build) + run: pnpm build + + docker-build: + name: Docker Build + runs-on: ubuntu-latest + needs: type-safety-and-deps + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Install dependencies + run: pnpm install + + - name: Build Docker image + run: docker build -t studio-lite:latest . \ No newline at end of file diff --git a/.github/workflows/dependency_builder.yml b/.github/workflows/dependency_builder.yml deleted file mode 100644 index 1a0cfcf..0000000 --- a/.github/workflows/dependency_builder.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Type Safety & Dependency Test - -on: - push: - pull_request: - -jobs: - type-safety-and-deps: - name: Type Safety & Dependency Test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install pnpm - run: npm install -g pnpm - - - name: Install dependencies - run: pnpm install - - - name: Type Safety Check (pnpm build) - run: pnpm build \ No newline at end of file diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml deleted file mode 100644 index 6a94003..0000000 --- a/.github/workflows/docker_build.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Docker Build - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - docker-build: - name: Docker Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install pnpm - run: npm install -g pnpm - - - name: Install dependencies - run: pnpm install - - - name: Build Docker image - run: docker build -t studio-lite:latest . \ No newline at end of file