-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
241 lines (232 loc) · 10.8 KB
/
docker-compose.yml
File metadata and controls
241 lines (232 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# SourceBridge Docker Compose
#
# Quick start:
# cp .env.example .env # (optional) customize LLM provider, API keys
# docker compose up -d
#
# By default the worker uses Ollama for LLM inference (no API key required).
# To use Anthropic or another cloud provider, set the variables in .env or
# export them in your shell before running `docker compose up`.
#
# See docs/installation.md for full configuration reference.
services:
surrealdb-init:
image: alpine:3.20
command:
- /bin/sh
- -lc
- mkdir -p /data/database.db && chown -R 65532:65532 /data
volumes:
- surrealdb-data:/data
restart: "no"
# Generate a per-install encryption key on first boot (see docker-compose.hub.yml
# for the full comment). Resolution order: if SOURCEBRIDGE_SECURITY_ENCRYPTION_KEY
# is set in .env, the file key is also generated but the literal env var wins
# per r1 H2 (*_FILE > literal env > empty). See docs/admin/llm-config.md.
encryption-key-init:
image: alpine:3.20
command:
- /bin/sh
- -lc
- |
if [ ! -f /secrets/encryption_key ]; then
head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n' > /secrets/encryption_key
echo "encryption-key-init: generated new encryption key"
else
echo "encryption-key-init: encryption key already exists, skipping"
fi
# Allow the API user (UID 1000) to read the key. The file is
# in a named volume only accessible within the compose network.
chown 1000:1000 /secrets/encryption_key
chmod 600 /secrets/encryption_key
volumes:
- sourcebridge-secrets:/secrets
restart: "no"
# SurrealDB — embedded document/graph database
surrealdb:
image: surrealdb/surrealdb:v2.6.5
# CA-229: SurrealDB credentials default to root/root (development) but
# are now env-overridable. Production-shaped operator who wants to
# harden the dev compose can set SURREAL_USER and SURREAL_PASS in
# .env. The published port is also opt-in via SOURCEBRIDGE_SURREALDB_PORT
# (default 8000); set to "127.0.0.1:8000" to bind loopback-only when
# exposing dev services to a wider network is undesirable.
command: start --user ${SURREAL_USER:-root} --pass ${SURREAL_PASS:-root} --log info file:/data/database.db
ports:
- "${SOURCEBRIDGE_SURREALDB_PORT:-8000}:8000"
volumes:
- surrealdb-data:/data
depends_on:
surrealdb-init:
condition: service_completed_successfully
restart: unless-stopped
healthcheck:
test: ["CMD", "/surreal", "is-ready", "--endpoint", "ws://localhost:8000"]
interval: 5s
timeout: 5s
retries: 24
start_period: 20s
# SourceBridge API — Go HTTP/GraphQL server
sourcebridge:
build:
context: .
dockerfile: deploy/docker/Dockerfile.sourcebridge
# CA-136: pass through version metadata so docker compose builds
# bake real values into the binary and OCI labels. Defaults
# preserve raw `docker compose up` behavior — the resulting image
# is labeled "0.0.0-local"/"unknown". Use `make docker-build` to
# have the Makefile compute and inject git-derived values.
args:
VERSION: ${VERSION:-0.0.0-local}
COMMIT: ${COMMIT:-unknown}
BUILD_DATE: ${BUILD_DATE:-unknown}
EDITION: ${EDITION:-oss}
ports:
- "${SOURCEBRIDGE_API_PORT:-8080}:8080"
environment:
- SOURCEBRIDGE_PPROF_ENABLED=${SOURCEBRIDGE_PPROF_ENABLED:-false}
- SOURCEBRIDGE_STORAGE_SURREAL_MODE=external
- SOURCEBRIDGE_STORAGE_SURREAL_URL=ws://surrealdb:8000/rpc
- SOURCEBRIDGE_STORAGE_SURREAL_NAMESPACE=sourcebridge
- SOURCEBRIDGE_STORAGE_SURREAL_DATABASE=sourcebridge
- SOURCEBRIDGE_STORAGE_SURREAL_USER=${SURREAL_USER:-root}
- SOURCEBRIDGE_STORAGE_SURREAL_PASS=${SURREAL_PASS:-root}
- SOURCEBRIDGE_STORAGE_REDIS_MODE=memory
# Repo cache: /data is owned by the 'sourcebr' user (UID 1000) inside the
# API container. Without this, the default './repo-cache' resolves to
# /repo-cache (root-owned) and every addRepository call fails with
# "permission denied" before the git clone even starts.
# Note: /data/repo-cache lives inside the container filesystem and is NOT
# persisted across container restarts by default. The cache is fully
# rebuildable from git, so this is acceptable. If you want crash-safe
# caching, add a named volume mount for /data/repo-cache.
- SOURCEBRIDGE_STORAGE_REPO_CACHE_PATH=/data/repo-cache
- SOURCEBRIDGE_WORKER_ADDRESS=worker:50051
- SOURCEBRIDGE_SECURITY_GRPC_AUTH_SECRET=${SOURCEBRIDGE_GRPC_SECRET:-dev-shared-secret}
# CA-311: 64-hex placeholder is syntactically valid (32 raw bytes; passes
# the >=32-byte length gate) but is publicly known. Override with
# SOURCEBRIDGE_JWT_SECRET=$(openssl rand -hex 32) in .env for any
# non-throwaway use. WarnInsecureDefaults emits a startup banner when
# this exact placeholder is detected at runtime.
- SOURCEBRIDGE_SECURITY_JWT_SECRET=${SOURCEBRIDGE_JWT_SECRET:-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef}
# r1 M3: explicit env wiring so docker-compose substitutes from .env.
# The :- default keeps the line valid when .env is absent.
# Resolution order (ResolveEncryptionKey): _FILE > literal env > empty.
# When both are set, the FILE wins and the literal env is ignored — this
# matches the Vault / Postgres *_FILE convention (files are higher-trust
# than env vars, which leak via docker inspect and /proc).
# setup.sh writes the literal env into .env AND the init container
# generates the volume file; when both exist, the file takes precedence.
# To rotate: update the volume file (or run down -v and up to regenerate).
# Updating .env alone has no effect while the volume file is present.
- SOURCEBRIDGE_SECURITY_ENCRYPTION_KEY=${SOURCEBRIDGE_SECURITY_ENCRYPTION_KEY:-}
# r1 Phase 2: file path for the init-container-generated encryption key.
# The file is the primary source of truth; literal env is the operator
# escape hatch when no volume file is present (e.g. external secret manager).
- SOURCEBRIDGE_SECURITY_ENCRYPTION_KEY_FILE=/run/sourcebridge/secrets/encryption_key
volumes:
- sourcebridge-secrets:/run/sourcebridge/secrets:ro
depends_on:
surrealdb:
condition: service_healthy
encryption-key-init:
condition: service_completed_successfully
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
# SourceBridge Worker — Python gRPC service for AI reasoning
worker:
build:
context: .
dockerfile: deploy/docker/Dockerfile.worker
args:
VERSION: ${VERSION:-0.0.0-local}
COMMIT: ${COMMIT:-unknown}
BUILD_DATE: ${BUILD_DATE:-unknown}
EDITION: ${EDITION:-oss}
ports:
- "${SOURCEBRIDGE_WORKER_PORT:-50051}:50051"
environment:
- SOURCEBRIDGE_WORKER_GRPC_PORT=50051
- SOURCEBRIDGE_WORKER_SURREAL_URL=ws://surrealdb:8000/rpc
- SOURCEBRIDGE_WORKER_SURREAL_NAMESPACE=sourcebridge
- SOURCEBRIDGE_WORKER_SURREAL_DATABASE=sourcebridge
- SOURCEBRIDGE_WORKER_SURREAL_USER=${SURREAL_USER:-root}
- SOURCEBRIDGE_WORKER_SURREAL_PASS=${SURREAL_PASS:-root}
- SOURCEBRIDGE_WORKER_GRPC_AUTH_SECRET=${SOURCEBRIDGE_GRPC_SECRET:-dev-shared-secret}
# SEC-11: enable gRPC reflection in dev so grpcurl / grpc-ui work locally.
# Production deployments leave this unset → reflection is off.
# CA-317: dev-default true (verbose worker logging is useful in dev
# compose), but operator-overridable. Set SOURCEBRIDGE_WORKER_DEBUG=false
# in .env when running this compose against a non-dev workload.
- SOURCEBRIDGE_WORKER_DEBUG=${SOURCEBRIDGE_WORKER_DEBUG:-true}
# ─── LLM Provider Configuration ──────────────────────────────────
#
# Option A: Cloud — Anthropic (recommended for best quality)
# Set ANTHROPIC_API_KEY in your environment or .env file.
#
# - SOURCEBRIDGE_WORKER_LLM_PROVIDER=anthropic
# - SOURCEBRIDGE_WORKER_LLM_BASE_URL=
# - SOURCEBRIDGE_WORKER_LLM_MODEL=claude-sonnet-4-20250514
# - SOURCEBRIDGE_WORKER_LLM_API_KEY=${ANTHROPIC_API_KEY}
#
# Option B: Local — Ollama (default, no API key needed)
# Requires Ollama running locally: https://ollama.com
# Pull a model first: ollama pull qwen3:32b
#
- SOURCEBRIDGE_WORKER_LLM_PROVIDER=${SOURCEBRIDGE_LLM_PROVIDER:-ollama}
- SOURCEBRIDGE_WORKER_LLM_BASE_URL=${SOURCEBRIDGE_LLM_BASE_URL:-http://host.docker.internal:11434/v1}
- SOURCEBRIDGE_WORKER_LLM_MODEL=${SOURCEBRIDGE_LLM_MODEL:-qwen3:32b}
- SOURCEBRIDGE_WORKER_LLM_API_KEY=${SOURCEBRIDGE_LLM_API_KEY:-not-needed}
# ─── Embedding Provider ──────────────────────────────────────────
- SOURCEBRIDGE_WORKER_EMBEDDING_PROVIDER=${SOURCEBRIDGE_EMBEDDING_PROVIDER:-ollama}
- SOURCEBRIDGE_WORKER_EMBEDDING_BASE_URL=${SOURCEBRIDGE_EMBEDDING_BASE_URL:-http://host.docker.internal:11434/v1}
- SOURCEBRIDGE_WORKER_EMBEDDING_MODEL=${SOURCEBRIDGE_EMBEDDING_MODEL:-nomic-embed-text}
- SOURCEBRIDGE_WORKER_EMBEDDING_API_KEY=${SOURCEBRIDGE_EMBEDDING_API_KEY:-not-needed}
depends_on:
surrealdb:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "/usr/local/bin/grpc_health_probe", "-addr=localhost:50051"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
# SourceBridge Web — Next.js dashboard
web:
build:
context: .
dockerfile: deploy/docker/Dockerfile.web
args:
VERSION: ${VERSION:-0.0.0-local}
COMMIT: ${COMMIT:-unknown}
BUILD_DATE: ${BUILD_DATE:-unknown}
EDITION: ${EDITION:-oss}
ports:
# Host port defaults to 3300 (3000 is commonly taken on dev machines).
# Override via SOURCEBRIDGE_WEB_PORT in .env if 3300 collides too.
# Container side stays 3000.
- "${SOURCEBRIDGE_WEB_PORT:-3300}:3000"
environment:
- NEXT_PUBLIC_API_URL=http://sourcebridge:8080
- SOURCEBRIDGE_WEB_DEV_PROXY=http://sourcebridge:8080
depends_on:
sourcebridge:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:3000"]
interval: 10s
timeout: 3s
retries: 5
start_period: 20s
volumes:
surrealdb-data:
# Per-install encryption key generated by encryption-key-init.
# Back this up before any restore. See docs/admin/llm-config.md.
sourcebridge-secrets: