Skip to content
Open
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
642 changes: 518 additions & 124 deletions README.md

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions mothership/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
dist
.git
.gitignore
*.md
.env*
data/
4 changes: 4 additions & 0 deletions mothership/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PORT=3001
JWT_SECRET=change-me-to-a-random-string

Choose a reason for hiding this comment

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

medium

While it's good practice to provide a placeholder secret in an example file, it's crucial to ensure a strong, unique secret is used in production. The current implementation in src/config.ts falls back to a weak, hardcoded secret if the environment variable is not set. This is a significant security risk. I've added a separate comment in src/config.ts with a suggestion to enforce setting a secret in production environments.

DB_PATH=./data/mothership.db
LOG_LEVEL=info
6 changes: 6 additions & 0 deletions mothership/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
dist/
data/*.db
data/*.db-wal
data/*.db-shm
.env
3 changes: 3 additions & 0 deletions mothership/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{$DOMAIN:localhost} {
reverse_proxy mothership:3001
}
28 changes: 28 additions & 0 deletions mothership/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Multi-stage build for Regent Mothership

FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src/ ./src/
RUN npx tsc

FROM node:22-slim
RUN addgroup --system mothership && adduser --system --ingroup mothership mothership
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev && chown -R mothership:mothership /app
COPY --from=build --chown=mothership:mothership /app/dist/ ./dist/
COPY --chown=mothership:mothership src/db/migrations/ ./dist/db/migrations/

ENV PORT=3001
ENV DB_PATH=/data/mothership.db
ENV LOG_LEVEL=info
VOLUME /data

RUN mkdir -p /data && chown mothership:mothership /data

USER mothership

Choose a reason for hiding this comment

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

Correctness: Running as the non-root user mothership with the /data volume will cause runtime write errors because the mount defaults to root ownership, preventing the application from writing to the database at /data/mothership.db. Additionally, the chown command is ineffective because it follows the VOLUME declaration. Move the chown command before the VOLUME instruction and use an entrypoint script to handle permissions for bind mounts at runtime.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `mothership/Dockerfile` around line 26, running as non-root can’t write to `/data` when the Docker volume or bind mount is root-owned. Add a runtime chown step (entrypoint script or CMD wrapper that chowns /data before starting node), or ensure the volume is created with the mothership UID/GID. Keep the fix minimal and avoid unrelated changes.

EXPOSE 3001
CMD ["node", "dist/index.js"]
Empty file added mothership/data/.gitkeep
Empty file.
37 changes: 37 additions & 0 deletions mothership/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
services:
mothership:
build: .
ports:
- "3001:3001"
volumes:
- mothership-data:/data
environment:
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
- NODE_ENV=production
- DB_PATH=/data/mothership.db
- LOG_LEVEL=info
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3001/api/v1/health').then(r=>process.exit(r.ok?0:1))"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped

caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
- caddy-config:/config
depends_on:
mothership:
condition: service_healthy
restart: unless-stopped

volumes:
mothership-data:
caddy-data:
caddy-config:
Loading