Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.git
node_modules
.next
.env*
20 changes: 8 additions & 12 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,19 @@ jobs:
--config p/owasp-top-ten \
--config p/secrets

npm-audit:
name: npm audit
bun-audit:
name: bun audit
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: oven-sh/setup-bun@v2
with:
node-version: 20
- name: Audit (skip when no package.json)
run: |
if [ -f package.json ]; then
(npm ci --no-audit --no-fund 2>/dev/null || npm install --no-audit --no-fund)
npm audit --audit-level=critical
else
echo "no package.json — skipping npm audit"
fi
bun-version-file: package.json
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Audit dependencies
run: bun audit --audit-level=critical

gitleaks:
name: gitleaks
Expand Down
47 changes: 36 additions & 11 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,44 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
# The version comes from packageManager in package.json, the same Bun the
# image pins.
- uses: oven-sh/setup-bun@v2
with:
version: 10.32.1

- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
bun-version-file: package.json

- name: Install
run: pnpm install --frozen-lockfile
run: bun install --frozen-lockfile

# The suite runs with the quarantine list in vitest.config.js applied —
# see tests/QUARANTINE.md for what is excluded and why.
# vitest runs on the Bun runtime (`bun --bun vitest run`). The suite runs
# with the quarantine list in vitest.config.js applied; see
# tests/QUARANTINE.md for what is excluded and why.
- name: Run tests
run: pnpm test:ci
run: bun run test:ci

build:
name: build and boot under Bun
runs-on: ubuntu-latest
env:
# Placeholders: the build only needs the public values to exist.
NEXT_PUBLIC_SUPABASE_URL: https://example.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY: ci-placeholder
NEXT_PUBLIC_APP_URL: http://127.0.0.1:8080
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version-file: package.json
- run: bun install --frozen-lockfile
- run: bun run build
- name: Standalone server answers under Bun
run: |
cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/
(cd .next/standalone && PORT=8080 HOSTNAME=127.0.0.1 bun server.js > /tmp/server.log 2>&1 &)
for i in $(seq 1 30); do
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/ || true)
[ "$code" = 200 ] && { echo "/ -> $code"; exit 0; }
sleep 1
done
cat /tmp/server.log; exit 1
1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

131 changes: 50 additions & 81 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,106 +1,75 @@
# Use an official Node image with Corepack (pnpm) available
FROM node:24-bookworm-slim
# syntax=docker/dockerfile:1
#
# qrypt.chat on Bun: the Next.js standalone server runs under Bun beside a Tor
# hidden service (entrypoint.sh starts both).
#
# Contract with dev2 (/home/anthony/www/qrypt.chat), unchanged from the Node
# image: listens on 8080, answers / for the deploy health check, takes the
# NEXT_PUBLIC_*/PUBLIC_*/VITE_* build args the compose file passes, reads its
# secrets from app.env at run time, keeps the onion keys on the
# /var/lib/tor/hidden_service volume.

# System deps: tor + tini for clean PID 1 + gettext for envsubst
RUN apt-get update && apt-get install -y --no-install-recommends \
tor ca-certificates tini gettext-base \
&& rm -rf /var/lib/apt/lists/*

# Prepare Tor dirs (volume will mount at /var/lib/tor/hidden_service)
RUN mkdir -p /var/lib/tor/hidden_service /var/log/tor \
&& chown -R debian-tor:debian-tor /var/lib/tor /var/log/tor \
&& chmod 700 /var/lib/tor/hidden_service
FROM oven/bun:1.4.0-slim AS deps
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile

# Accept build arguments for environment variables
# Next.js NEXT_PUBLIC_* prefixed versions
FROM deps AS build
# Public values Next inlines into the client bundle at build time. These are
# the only build args dev2's compose passes; secrets stay runtime-only.
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY
ARG NEXT_PUBLIC_APP_URL
ARG NEXT_PUBLIC_APP_NAME
ARG NEXT_PUBLIC_APP_VERSION
ARG NEXT_PUBLIC_ONION_URL
# Legacy PUBLIC_* for backward compat
ARG PUBLIC_SUPABASE_URL
ARG PUBLIC_SUPABASE_ANON_KEY
ARG SUPABASE_SERVICE_ROLE_KEY
ARG SUPABASE_DB_PASSWORD
ARG SUPABASE_ACCESS_TOKEN
ARG SUPABASE_PROJECT_REF
ARG PROJECT_REF
ARG SUPABASE_JWT_DISCOVERY_URL
ARG GOTRUE_OTP_EXPIRY
ARG GOTRUE_DISABLE_SIGNUP
ARG PUBLIC_APP_URL
ARG PUBLIC_APP_NAME
ARG PUBLIC_APP_VERSION
ARG SITE_URL
ARG OPENAI_API_KEY
ARG SMTP_HOST
ARG SMTP_PORT
ARG SMTP_USER
ARG SMTP_PASS
ARG MAILGUN_API_KEY
ARG MAILGUN_DOMAIN
ARG FROM_EMAIL
ARG OTP_TO_EMAIL
ARG TWILIO_SID
ARG TWILIO_SECRET
ARG TWILIO_ACCOUNT_SID
ARG TWILIO_AUTH_TOKEN
ARG TWILIO_PHONE_NUMBER
ARG TWILIO_MESSAGE_SERVICE_SID
ARG ENABLE_PHONE_CONFIRMATIONS
ARG ENABLE_PHONE_CHANGE_CONFIRMATIONS
ARG SMS_TEMPLATE
ARG NODE_ENV
ARG VITE_LOG_LEVEL
ARG ENCRYPTION_KEY
ARG PUBLIC_ONION_URL

# Set environment variables for build (Next.js NEXT_PUBLIC_* and legacy PUBLIC_*)
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL
ENV NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY
ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL
ENV NEXT_PUBLIC_APP_NAME=$NEXT_PUBLIC_APP_NAME
ENV NEXT_PUBLIC_APP_VERSION=$NEXT_PUBLIC_APP_VERSION
ENV NEXT_PUBLIC_ONION_URL=$NEXT_PUBLIC_ONION_URL
# Fallback: also accept old PUBLIC_* names and map them
ENV PUBLIC_SUPABASE_URL=$PUBLIC_SUPABASE_URL
ENV PUBLIC_SUPABASE_ANON_KEY=$PUBLIC_SUPABASE_ANON_KEY
ENV PUBLIC_APP_URL=$PUBLIC_APP_URL
ENV PUBLIC_APP_NAME=$PUBLIC_APP_NAME
ENV PUBLIC_APP_VERSION=$PUBLIC_APP_VERSION
ENV PUBLIC_ONION_URL=$PUBLIC_ONION_URL
ENV NODE_ENV=$NODE_ENV

# App build
WORKDIR /app
# Copy lockfiles first for better caching
COPY pnpm-lock.yaml* package.json pnpm-workspace.yaml ./
# Pin pnpm to a known-good version. `pnpm@latest` pulls whatever's on
# the npm registry RIGHT NOW, so Railway can suddenly start failing
# when pnpm ships a stricter minor (e.g. ERR_PNPM_IGNORED_BUILDS hard-
# fail vs warn). Bump intentionally when we test a new version.
RUN corepack enable && corepack prepare pnpm@10.32.1 --activate
RUN pnpm install --frozen-lockfile

# Copy the rest and build
ARG VITE_LOG_LEVEL
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL \
NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY \
NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL \
NEXT_PUBLIC_APP_NAME=$NEXT_PUBLIC_APP_NAME \
NEXT_PUBLIC_APP_VERSION=$NEXT_PUBLIC_APP_VERSION \
NEXT_PUBLIC_ONION_URL=$NEXT_PUBLIC_ONION_URL \
PUBLIC_SUPABASE_URL=$PUBLIC_SUPABASE_URL \
PUBLIC_SUPABASE_ANON_KEY=$PUBLIC_SUPABASE_ANON_KEY \
PUBLIC_APP_URL=$PUBLIC_APP_URL \
PUBLIC_APP_NAME=$PUBLIC_APP_NAME \
PUBLIC_APP_VERSION=$PUBLIC_APP_VERSION \
PUBLIC_ONION_URL=$PUBLIC_ONION_URL \
NEXT_TELEMETRY_DISABLED=1
COPY . .
RUN pnpm build

# Runtime env
ENV HOST=0.0.0.0
ENV PORT=8080
# `bun --bun next build` (the build script): Next runs on Bun, not Node.
RUN bun run build

# Entrypoint
FROM oven/bun:1.4.0-slim AS runtime
# tor for the onion service, tini as PID 1.
RUN apt-get update && apt-get install -y --no-install-recommends \
tor ca-certificates tini \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /var/lib/tor/hidden_service /var/log/tor \
&& chown -R debian-tor:debian-tor /var/lib/tor /var/log/tor \
&& chmod 700 /var/lib/tor/hidden_service
WORKDIR /app
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
HOST=0.0.0.0 \
PORT=8080 \
HOSTNAME=0.0.0.0
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 8080
# Tor requires root at startup (chown /var/lib/tor, run tor daemon); entrypoint
# drops to debian-tor for the tor process. A non-root USER here would break it.
# nosemgrep: dockerfile.security.missing-user-entrypoint.missing-user-entrypoint
ENTRYPOINT ["/usr/bin/tini","--"]
# nosemgrep: dockerfile.security.missing-user.missing-user
CMD ["/entrypoint.sh"]

17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ A secure, privacy-focused chat application built with post-quantum cryptography
## 🚀 Quick Start

### Prerequisites
- Node.js 20+ (recommended)
- pnpm (recommended) or npm
- Bun 1.4 (package manager and runtime)
- Supabase account
- Twilio account (for SMS verification)

Expand All @@ -80,7 +79,7 @@ git clone https://github.com/yourusername/qryptchat.git
cd qryptchat

# Install dependencies
pnpm install
bun install

# Set up environment variables
cp .env.example .env
Expand All @@ -90,7 +89,7 @@ cp .env.example .env
pnpx supabase db reset

# Start development server
pnpm dev
bun dev
```

The app will be available at `http://localhost:8080` (or the PORT specified in your .env file).
Expand Down Expand Up @@ -167,7 +166,7 @@ TWILIO_PHONE_NUMBER=your_production_twilio_phone
Start your development server:

```bash
pnpm dev
bun dev
```

The app should now connect to your production Supabase instance. You can verify by:
Expand Down Expand Up @@ -211,16 +210,16 @@ QryptChat implements a **zero-knowledge post-quantum architecture** where:

```bash
# Start development server
pnpm dev
bun dev

# Run tests
pnpm test
bun run test

# Run tests with UI
pnpm test:ui
bun run test:ui

# Build for production
pnpm build
bun run build

# Preview production build
pnpm preview
Expand Down
Loading
Loading