-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
307 lines (297 loc) · 12.1 KB
/
Copy pathdocker-compose.yml
File metadata and controls
307 lines (297 loc) · 12.1 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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# AdvisoryHub local-dev compose file.
#
# This file is dev-only. Production deploys do NOT use it — they
# inject env vars through their own platform (Kubernetes Secrets,
# Docker Swarm secrets, AWS SSM Parameter Store, …). Therefore the
# values below are intentionally hard-coded with dev-fixture
# credentials; nothing in this file is sensitive.
#
# First-run flow:
#
# docker compose up -d kanidm
# bash dev/kanidm/setup.sh # mints the OIDC client secret
# docker compose up # web + worker pick it up
#
# After that, plain `docker compose up` is enough.
x-django-env: &django-env
# ---- Django ----
DJANGO_SECRET_KEY: dev-only-not-a-real-secret
DJANGO_DEBUG: "True"
DJANGO_ALLOWED_HOSTS: localhost,127.0.0.1,web
DJANGO_TIME_ZONE: UTC
# ---- Database & broker ----
DATABASE_URL: postgres://advisoryhub:advisoryhub@postgres:5432/advisoryhub
CELERY_BROKER_URL: redis://valkey:6379/0
CELERY_RESULT_BACKEND: redis://valkey:6379/1
CACHE_URL: redis://valkey:6379/2
CELERY_TASK_ALWAYS_EAGER: "False"
# ---- Email (console backend in dev) ----
EMAIL_BACKEND: django.core.mail.backends.console.EmailBackend
DEFAULT_FROM_EMAIL: AdvisoryHub <noreply@example.org>
# ---- Footer help links ----
# Issues + private-vuln-report links are derived from ADVISORYHUB_REPO_URL.
ADVISORYHUB_REPO_URL: https://github.com/eclipse-csi/advisoryhub
ADVISORYHUB_DISCUSSIONS_URL: https://github.com/orgs/eclipse-csi/discussions
# ---- OIDC (defaults match dev/kanidm/setup.sh) ----
# OIDC_RP_CLIENT_ID and OIDC_RP_CLIENT_SECRET are written by the
# bootstrap script into dev/kanidm/.env.kanidm; that file is loaded
# below via env_file (with required:false so first-time `docker
# compose up` doesn't fail before kanidm is bootstrapped).
# Browser-facing endpoint (the user is redirected here):
# /ui/oauth2 is kanidm's web flow that drives login+consent. The
# back-end /oauth2/authorise endpoint requires a Bearer token and
# is NOT what we want here.
OIDC_OP_AUTHORIZATION_ENDPOINT: https://localhost:8443/ui/oauth2
# Server-to-server endpoints — the web container talks to kanidm by
# service name on the docker network.
OIDC_OP_TOKEN_ENDPOINT: https://kanidm:8443/oauth2/token
OIDC_OP_USER_ENDPOINT: https://kanidm:8443/oauth2/openid/advisoryhub/userinfo
OIDC_OP_JWKS_ENDPOINT: https://kanidm:8443/oauth2/openid/advisoryhub/public_key.jwk
# Kanidm does NOT implement OIDC RP-initiated logout — its discovery doc has
# no usable end_session_endpoint (kanidm issues #1997 / #3752 / #4240). Its
# only logout is an interactive /ui/logout web page that ignores id_token_hint
# / post_logout_redirect_uri and never redirects back, which forced a
# confusing second click. Leave this empty in dev: accounts.auth.provider_logout
# then falls back to LOGOUT_REDIRECT_URL, so one click ends the Django session
# and lands on /accounts/signed-out/. The kanidm SSO cookie survives, so
# returning to a protected page silently re-auths via SSO (expected). To fully
# end the kanidm session in dev, sign out in the kanidm UI directly (or use a
# private window). In prod, set this to the real OP's OIDC end_session_endpoint.
OIDC_OP_LOGOUT_ENDPOINT: ""
OIDC_RP_SIGN_ALGO: ES256
OIDC_VERIFY_SSL: "False" # self-signed kanidm cert in dev
OIDC_GROUP_CLAIM: groups
OIDC_ADMIN_GROUP: advisoryhub-security
# ---- Operability (looser in dev) ----
LOG_FORMAT: plain # "json" in production
LOG_LEVEL: INFO
RATELIMIT_ENABLE: "False"
STEP_UP_REQUIRED: "False"
STEP_UP_MAX_AGE_SECONDS: "300"
READYZ_INCLUDE_PUB_REPO: "False"
SENTRY_DSN: "" # disabled in dev
# ---- Publication (Phase D) — empty in dev unless you wire it up ----
PUB_REPO_URL: ""
PUB_REPO_BRANCH: main
PUB_REPO_AUTH: ssh
PUB_REPO_SSH_KEY_PATH: ""
PUB_REPO_TOKEN: ""
PUB_COMMIT_AUTHOR_NAME: AdvisoryHub Bot
PUB_COMMIT_AUTHOR_EMAIL: advisoryhub-bot@example.org
PUB_OSV_PATH_TEMPLATE: osv/{advisory_id}.json
PUB_CSAF_PATH_TEMPLATE: csaf/{advisory_id}.json
# ---- GHSA integration (off by default in dev) ----
# Flip GHSA_FEATURE_ENABLED to True after registering a sandbox GitHub
# App and installing it on one or more test repos. The App private key
# is the only sensitive credential here — never commit it; mount it as
# a file or paste it (only for short-lived dev experiments).
GHSA_FEATURE_ENABLED: "False"
GITHUB_APP_ID: "0"
GITHUB_APP_PRIVATE_KEY_PATH: ""
GITHUB_APP_PRIVATE_KEY: ""
GITHUB_APP_WEBHOOK_SECRET: ""
GITHUB_APP_API_BASE_URL: https://api.github.com
PMI_API_BASE_URL: https://projects.eclipse.org/api
PMI_API_TOKEN: ""
PMI_SYNC_INTERVAL_HOURS: "6"
# Security-team roster sync — off in dev (no Eclipse API creds). Flip
# PMI_ROSTER_SYNC_ENABLED to "True" and fill the ECLIPSE_API_* creds to try it.
PMI_ROSTER_SYNC_ENABLED: "False"
PMI_ROSTER_SYNC_INTERVAL_HOURS: "24"
ECLIPSE_API_BASE_URL: https://api.eclipse.org
ECLIPSE_API_TOKEN_URL: https://auth.eclipse.org/auth/realms/eclipse/protocol/openid-connect/token
ECLIPSE_API_CLIENT_ID: ""
ECLIPSE_API_CLIENT_SECRET: ""
ECLIPSE_API_SCOPE: ""
# ---- LLM-assisted duplicate detection (off by default in dev) ----
# Flip SIMILARITY_CHECK_ENABLED to "True" and set an API key — or keep
# content local with SIMILARITY_LLM_PROVIDER=openai plus a
# SIMILARITY_LLM_BASE_URL pointing at an OpenAI-compatible server
# (Ollama, vLLM, LM Studio). When enabled, advisory content is sent to
# the configured provider on every check.
SIMILARITY_CHECK_ENABLED: "False"
SIMILARITY_LLM_PROVIDER: anthropic
SIMILARITY_LLM_MODEL: claude-opus-4-8
SIMILARITY_LLM_API_KEY: ""
SIMILARITY_LLM_BASE_URL: ""
SIMILARITY_LLM_TIMEOUT: "120"
SIMILARITY_CANDIDATE_LIMIT: "60"
SIMILARITY_MIN_CONFIDENCE: "20"
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: advisoryhub
POSTGRES_PASSWORD: advisoryhub
POSTGRES_DB: advisoryhub
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U advisoryhub"]
interval: 5s
timeout: 5s
retries: 5
valkey:
image: valkey/valkey:8
# One instance backs the Celery broker (db0), result backend (db1) and cache
# (db2). Pin noeviction (the default) explicitly so an eviction can never
# silently drop broker messages or rate-limit/maintenance keys; in prod set
# this on the managed instance too (see docs/specification/architecture.md).
command: ["valkey-server", "--maxmemory-policy", "noeviction"]
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
# ------------------------------------------------------------------
# Dev-only OIDC provider. See dev/kanidm/README.md.
# Run `bash dev/kanidm/setup.sh` once after the container is up to
# generate the TLS cert, recover admin, and seed users + OAuth2 client.
# ------------------------------------------------------------------
kanidm:
# Pinned (not :latest) so Dependabot's docker-compose ecosystem can propose
# bumps; dev/kanidm/setup.sh targets kanidmd 1.10.x.
image: kanidm/server:1.10.4
ports:
- "8443:8443"
volumes:
- kanidm-data:/data
- ./dev/kanidm/server.toml:/data/server.toml:ro
environment:
KANIDM_DOMAIN: localhost
healthcheck:
test: ["CMD", "sh", "-c", "curl -fsk https://localhost:8443/status || exit 1"]
interval: 10s
timeout: 5s
retries: 12
start_period: 30s
web:
build:
context: .
# The Dockerfile's default (last) target is the production image; the
# dev target is deps-only and expects the source bind-mounted at /app.
target: dev
command: python manage.py runserver 0.0.0.0:8000
environment: *django-env
env_file:
# OIDC_RP_CLIENT_ID / OIDC_RP_CLIENT_SECRET written by
# dev/kanidm/setup.sh. required:false → compose tolerates the
# file's absence on a brand-new clone, before bootstrap runs.
- path: ./dev/kanidm/.env.kanidm
required: false
ports:
- "8000:8000"
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
volumes:
- .:/app
worker:
build:
context: .
# The Dockerfile's default (last) target is the production image; the
# dev target is deps-only and expects the source bind-mounted at /app.
target: dev
# --pool=threads: all tasks run in one process (worker threads), so the
# single metrics exporter on PROMETHEUS_WORKER_METRICS_PORT sees every
# task's counts and --concurrency can be raised freely. Our tasks are
# I/O-bound (git push, GHSA/PMI API, email), which the threads pool suits.
# (The default prefork pool forks separate processes whose metrics a single
# exporter can't see — see common/celery_metrics.py.)
command: celery -A config worker -l info --pool=threads --concurrency=4
environment:
<<: *django-env
PROMETHEUS_WORKER_METRICS_PORT: "9808"
env_file:
- path: ./dev/kanidm/.env.kanidm
required: false
ports:
- "9808:9808" # worker-local Prometheus exporter
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
volumes:
- .:/app
# Celery beat — fires the periodic tasks in CELERY_BEAT_SCHEDULE (backlog
# gauge refresh, access-log partition maintenance, PMI sync). The dev stack
# previously had no beat, so those tasks never ran locally.
beat:
build:
context: .
# The Dockerfile's default (last) target is the production image; the
# dev target is deps-only and expects the source bind-mounted at /app.
target: dev
command: celery -A config beat -l info --schedule=/tmp/celerybeat-schedule
environment: *django-env
env_file:
- path: ./dev/kanidm/.env.kanidm
required: false
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
volumes:
- .:/app
# ------------------------------------------------------------------
# Dev/demo observability (opt-in). NOT started by `docker compose up`
# or `mise run up`; bring it up with the `observability` profile:
# docker compose --profile observability up prometheus grafana
# (or `mise run obs-up`)
# Production does NOT use these — the operator scrapes /metrics with
# their own Prometheus. See dev/observability/README.md.
# ------------------------------------------------------------------
prometheus:
image: prom/prometheus:v2.54.1
profiles: ["observability"]
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=7d" # small local window in dev
ports:
- "9090:9090"
volumes:
- ./dev/observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./dev/observability/rules:/etc/prometheus/rules:ro
- prometheus-data:/prometheus
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:9090/-/healthy"]
interval: 10s
timeout: 5s
retries: 6
grafana:
image: grafana/grafana:11.2.0
profiles: ["observability"]
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: admin # dev-fixture cred, like postgres/valkey
GF_AUTH_ANONYMOUS_ENABLED: "true" # demo: read-only dashboards without login
GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer
GF_USERS_DEFAULT_THEME: light
ports:
- "3000:3000"
volumes:
- ./dev/observability/grafana/provisioning:/etc/grafana/provisioning:ro
- ./dev/observability/grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana-data:/var/lib/grafana
depends_on:
prometheus:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:3000/api/health || exit 1"]
interval: 10s
timeout: 5s
retries: 6
volumes:
pgdata:
kanidm-data:
prometheus-data:
grafana-data: