diff --git a/.gitignore b/.gitignore index 7787ba754..c752c12e6 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,5 @@ blob-report/ # Misc *.pem + +docker-compose.override.yml \ No newline at end of file diff --git a/DISCLAIMER.md b/DISCLAIMER.md index 0614214f4..95ef7d168 100644 --- a/DISCLAIMER.md +++ b/DISCLAIMER.md @@ -30,6 +30,26 @@ Before running Automaker, we strongly recommend reviewing the source code yourse - **Virtual Machine**: Use a VM (such as VirtualBox, VMware, or Parallels) to create an isolated environment - **Cloud Development Environment**: Use a cloud-based development environment that provides isolation +#### Running in Isolated Docker Container + +For maximum security, run Automaker in an isolated Docker container that **cannot access your laptop's files**: + +```bash +# 1. Set your API key (bash/Linux/Mac - creates UTF-8 file) +echo "ANTHROPIC_API_KEY=your-api-key-here" > .env + +# On Windows PowerShell, use instead: +Set-Content -Path .env -Value "ANTHROPIC_API_KEY=your-api-key-here" -Encoding UTF8 + +# 2. Build and run isolated container +docker-compose up -d + +# 3. Access the UI at http://localhost:3007 +# API at http://localhost:3008/api/health +``` + +The container uses only Docker-managed volumes and has no access to your host filesystem. See [docker-isolation.md](docs/docker-isolation.md) for full documentation. + ### 3. Limit Access If you must run locally: diff --git a/README.md b/README.md index 39c31d4b9..1fbee03ab 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ The future of software development is **agentic coding**—where developers beco > > **We do not recommend running Automaker directly on your local computer** due to the risk of AI agents having access to your entire file system. Please sandbox this application using Docker or a virtual machine. > -> **[Read the full disclaimer](../DISCLAIMER.md)** +> **[Read the full disclaimer](./DISCLAIMER.md)** --- diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile index 6f909af4b..8c019a2f5 100644 --- a/apps/server/Dockerfile +++ b/apps/server/Dockerfile @@ -4,11 +4,15 @@ # Build stage FROM node:20-alpine AS builder +# Install build dependencies for native modules (node-pty) +RUN apk add --no-cache python3 make g++ + WORKDIR /app -# Copy package files +# Copy package files and scripts needed for postinstall COPY package*.json ./ COPY apps/server/package*.json ./apps/server/ +COPY scripts ./scripts # Install dependencies RUN npm ci --workspace=apps/server diff --git a/apps/ui/Dockerfile b/apps/ui/Dockerfile new file mode 100644 index 000000000..3ccd09c77 --- /dev/null +++ b/apps/ui/Dockerfile @@ -0,0 +1,43 @@ +# Automaker UI +# Multi-stage build for minimal production image + +# Build stage +FROM node:20-alpine AS builder + +# Install build dependencies +RUN apk add --no-cache python3 make g++ + +WORKDIR /app + +# Copy package files +COPY package*.json ./ +COPY apps/ui/package*.json ./apps/ui/ +COPY scripts ./scripts + +# Install dependencies (skip electron postinstall) +RUN npm ci --workspace=apps/ui --ignore-scripts + +# Copy source +COPY apps/ui ./apps/ui + +# Build for web (skip electron) +# VITE_SERVER_URL tells the UI where to find the API server +# Using localhost:3008 since both containers expose ports to the host +# Use ARG to allow overriding at build time: --build-arg VITE_SERVER_URL=http://api.example.com +ARG VITE_SERVER_URL=http://localhost:3008 +ENV VITE_SKIP_ELECTRON=true +ENV VITE_SERVER_URL=${VITE_SERVER_URL} +RUN npm run build --workspace=apps/ui + +# Production stage - serve with nginx +FROM nginx:alpine + +# Copy built files +COPY --from=builder /app/apps/ui/dist /usr/share/nginx/html + +# Copy nginx config for SPA routing +COPY apps/ui/nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/ui/nginx.conf b/apps/ui/nginx.conf new file mode 100644 index 000000000..2d96d1589 --- /dev/null +++ b/apps/ui/nginx.conf @@ -0,0 +1,10 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example new file mode 100644 index 000000000..9a6fc2301 --- /dev/null +++ b/docker-compose.override.yml.example @@ -0,0 +1,10 @@ +services: + server: + volumes: + # Mount your workspace directory to /projects inside the container + - /Users/webdevcody/Workspace/automaker-workspace:/projects:rw + environment: + # Set workspace directory so the UI can discover projects + - WORKSPACE_DIR=/projects + # Ensure /projects is in allowed directories + - ALLOWED_PROJECT_DIRS=/projects diff --git a/docker-compose.yml b/docker-compose.yml index 5a82f5999..3edbcd4e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,27 @@ # Automaker Docker Compose -# For self-hosting the Automaker backend server +# Runs Automaker in complete isolation from your host filesystem. +# The container cannot access any files on your laptop - only Docker-managed volumes. +# +# Usage: +# docker-compose up -d +# Then open http://localhost:3007 +# +# See docs/docker-isolation.md for full documentation. services: + # Frontend UI + ui: + build: + context: . + dockerfile: apps/ui/Dockerfile + container_name: automaker-ui + restart: unless-stopped + ports: + - "3007:80" + depends_on: + - server + + # Backend API Server server: build: context: . @@ -17,10 +37,11 @@ services: # Optional - authentication (leave empty to disable) - AUTOMAKER_API_KEY=${AUTOMAKER_API_KEY:-} - # Optional - restrict to specific directories (comma-separated) + # Optional - restrict to specific directories within container only + # These paths are INSIDE the container, not on your host - ALLOWED_PROJECT_DIRS=${ALLOWED_PROJECT_DIRS:-/projects} - # Optional - data directory for sessions, etc. + # Optional - data directory for sessions, etc. (container-only) - DATA_DIR=/data # Optional - CORS origin (default allows all) @@ -30,11 +51,20 @@ services: - OPENAI_API_KEY=${OPENAI_API_KEY:-} - GOOGLE_API_KEY=${GOOGLE_API_KEY:-} volumes: - # Persist data between restarts + # ONLY named volumes - these are isolated from your host filesystem + # This volume persists data between restarts but is container-managed - automaker-data:/data - # Mount your projects directory (read-write access) - - ${PROJECTS_DIR:-./projects}:/projects + # NO host directory mounts - container cannot access your laptop files + # If you need to work on a project, create it INSIDE the container + # or use a separate docker-compose override file + + # Security: Server runs as non-root user (already set in Dockerfile) + # Security: No privileged mode + # Security: No host network access + # Security: No host filesystem mounts volumes: automaker-data: + name: automaker-data + # Named volume - completely isolated from host filesystem diff --git a/docs/docker-isolation.md b/docs/docker-isolation.md new file mode 100644 index 000000000..5ebd4c71b --- /dev/null +++ b/docs/docker-isolation.md @@ -0,0 +1,66 @@ +# Docker Isolation Guide + +This guide covers running Automaker in a fully isolated Docker container. For background on why isolation matters, see the [Security Disclaimer](../DISCLAIMER.md). + +## Quick Start + +1. **Set your API key** (create a `.env` file in the project root): + + ```bash + # Linux/Mac + echo "ANTHROPIC_API_KEY=your-api-key-here" > .env + + # Windows PowerShell + Set-Content -Path .env -Value "ANTHROPIC_API_KEY=your-api-key-here" -Encoding UTF8 + ``` + +2. **Build and run**: + + ```bash + docker-compose up -d + ``` + +3. **Access Automaker** at `http://localhost:3007` + +4. **Stop**: + + ```bash + docker-compose down + ``` + +## How Isolation Works + +The default `docker-compose.yml` configuration: + +- Uses only Docker-managed volumes (no host filesystem access) +- Server runs as a non-root user +- Has no privileged access to your system + +Projects created in the UI are stored inside the container at `/projects` and persist across restarts via Docker volumes. + +## Mounting a Specific Project + +If you need to work on a host project, create `docker-compose.project.yml`: + +```yaml +services: + server: + volumes: + - ./my-project:/projects/my-project:ro # :ro = read-only +``` + +Then run: + +```bash +docker-compose -f docker-compose.yml -f docker-compose.project.yml up -d +``` + +**Tip**: Use `:ro` (read-only) when possible for extra safety. + +## Troubleshooting + +| Problem | Solution | +| --------------------- | -------------------------------------------------------------------------------------------- | +| Container won't start | Check `.env` has `ANTHROPIC_API_KEY` set. Run `docker-compose logs` for errors. | +| Can't access web UI | Verify container is running with `docker ps \| grep automaker` | +| Need a fresh start | Run `docker-compose down && docker volume rm automaker-data && docker-compose up -d --build` |