-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdocker-compose.e2e.yaml
More file actions
353 lines (331 loc) · 11.9 KB
/
Copy pathdocker-compose.e2e.yaml
File metadata and controls
353 lines (331 loc) · 11.9 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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# MoltNet Docker Compose — E2E Testing
#
# Full stack (infra + apps) with ephemeral storage.
# Data is reset on every restart.
#
# Repo-built app images are NOT built by Compose. They are produced by Nx
# (`docker:build`) and tagged `ghcr.io/getlarge/themoltnet/<svc>:dev` by
# `pnpm run e2e:build`. This file references them via `image:`. See issue #1498
# and AGENTS.md → "Docker image contract". This single file is used both
# locally and in CI; CI overrides the tags by exporting the *_IMAGE env vars
# (e.g. REST_API_IMAGE=ghcr.io/getlarge/themoltnet/rest-api:ci-<sha>).
#
# Usage (local):
# pnpm run e2e:up # builds images via Nx, then starts the stack
# pnpm run e2e:down # stops + removes volumes
# pnpm run e2e:reset # down + up
#
# Or directly, after `pnpm run e2e:build`:
# COMPOSE_DISABLE_ENV_FILE=true docker compose -f docker-compose.e2e.yaml up -d
# COMPOSE_DISABLE_ENV_FILE=true docker compose -f docker-compose.e2e.yaml down -v
services:
app-db:
extends:
file: docker-compose.base.yaml
service: app-db
app-db-migrate:
extends:
file: docker-compose.base.yaml
service: app-db-migrate
# Use the Nx-built image (db-migrate) instead of Compose building the base
# service's Dockerfile. !reset null drops the inherited build: block.
build: !reset null
image: ${DB_MIGRATE_IMAGE:-ghcr.io/getlarge/themoltnet/db-migrate:dev}
depends_on:
app-db:
condition: service_healthy
restart: 'on-failure:3'
issue-lifecycle-db:
extends:
file: docker-compose.base.yaml
service: issue-lifecycle-db
issue-lifecycle-db-migrate:
extends:
file: docker-compose.base.yaml
service: issue-lifecycle-db-migrate
depends_on:
issue-lifecycle-db:
condition: service_healthy
restart: 'on-failure:3'
kratos-postgres:
extends:
file: docker-compose.base.yaml
service: kratos-postgres
kratos-migrate:
extends:
file: docker-compose.base.yaml
service: kratos-migrate
depends_on:
kratos-postgres:
condition: service_healthy
restart: 'on-failure:3'
kratos:
extends:
file: docker-compose.base.yaml
service: kratos
environment:
SELFSERVICE_FLOWS_VERIFICATION_ENABLED: 'true'
SELFSERVICE_FLOWS_REGISTRATION_AFTER_OIDC_HOOKS_0_CONFIG_URL: http://rest-api:8080/hooks/kratos/after-registration
SELFSERVICE_FLOWS_REGISTRATION_AFTER_PASSWORD_HOOKS_0_CONFIG_URL: http://rest-api:8080/hooks/kratos/after-registration
SELFSERVICE_FLOWS_LOGIN_AFTER_OIDC_HOOKS_0_CONFIG_URL: http://rest-api:8080/hooks/kratos/after-login
SELFSERVICE_FLOWS_LOGIN_AFTER_PASSWORD_HOOKS_0_CONFIG_URL: http://rest-api:8080/hooks/kratos/after-login
SELFSERVICE_FLOWS_SETTINGS_AFTER_PASSWORD_HOOKS_0_CONFIG_URL: http://rest-api:8080/hooks/kratos/validate-settings
SELFSERVICE_FLOWS_SETTINGS_AFTER_PASSWORD_HOOKS_1_CONFIG_URL: http://rest-api:8080/hooks/kratos/after-settings
SELFSERVICE_FLOWS_SETTINGS_AFTER_PROFILE_HOOKS_0_CONFIG_URL: http://rest-api:8080/hooks/kratos/validate-settings
SELFSERVICE_FLOWS_SETTINGS_AFTER_PROFILE_HOOKS_1_CONFIG_URL: http://rest-api:8080/hooks/kratos/after-settings
depends_on:
kratos-migrate:
condition: service_completed_successfully
mailslurper:
condition: service_started
kratos-selfservice-ui-node:
extends:
file: docker-compose.base.yaml
service: kratos-selfservice-ui-node
environment:
KRATOS_PUBLIC_URL: http://kratos:4433/
depends_on:
kratos:
condition: service_healthy
hydra-postgres:
extends:
file: docker-compose.base.yaml
service: hydra-postgres
hydra-migrate:
extends:
file: docker-compose.base.yaml
service: hydra-migrate
depends_on:
hydra-postgres:
condition: service_healthy
restart: 'on-failure:3'
hydra:
extends:
file: docker-compose.base.yaml
service: hydra
environment:
URLS_SELF_ISSUER: http://hydra:4444
URLS_SELF_PUBLIC: http://hydra:4444
depends_on:
hydra-migrate:
condition: service_completed_successfully
keto-postgres:
extends:
file: docker-compose.base.yaml
service: keto-postgres
keto-migrate:
extends:
file: docker-compose.base.yaml
service: keto-migrate
depends_on:
keto-postgres:
condition: service_healthy
restart: 'on-failure:3'
keto:
extends:
file: docker-compose.base.yaml
service: keto
depends_on:
keto-migrate:
condition: service_completed_successfully
# Talos declares /var/lib/talos as an image VOLUME. Override it with tmpfs so
# CI/e2e cannot reuse a development named volume and all state is ephemeral.
talos:
extends:
file: docker-compose.base.yaml
service: talos
tmpfs:
- /var/lib/talos:uid=65532,gid=65532,mode=0700
mailslurper:
extends:
file: docker-compose.base.yaml
service: mailslurper
redis:
extends:
file: docker-compose.base.yaml
service: redis
# Host port (6380 to avoid colliding with a local dev redis on 6379) so the
# rate-limit e2e can inspect that limiter keys actually land in Redis.
ports:
- '6380:6379'
runtime-object-store:
extends:
file: docker-compose.base.yaml
service: runtime-object-store
rest-api:
image: ${REST_API_IMAGE:-ghcr.io/getlarge/themoltnet/rest-api:dev}
ports:
- '8080:8080'
environment:
NODE_ENV: test
PORT: '8080'
DATABASE_URL: postgresql://moltnet:moltnet_secret@app-db:5432/moltnet
DBOS_SYSTEM_DATABASE_URL: postgresql://moltnet:moltnet_secret@app-db:5432/moltnet?schema=dbos
ORY_KRATOS_PUBLIC_URL: http://kratos:4433
ORY_KRATOS_ADMIN_URL: http://kratos:4434
ORY_HYDRA_PUBLIC_URL: http://hydra:4444
ORY_HYDRA_ADMIN_URL: http://hydra:4445
ORY_KETO_PUBLIC_URL: http://keto:4466
ORY_KETO_ADMIN_URL: http://keto:4467
ORY_TALOS_ADMIN_URL: http://talos:4420
# Integration tests assert immediate revocation. Production keeps the
# documented 60-second positive-cache window; TTL zero still exercises
# single-flight request coalescing without retaining positive entries.
ORY_AUTH_CACHE_TTL_MS: '0'
ORY_ACTION_API_KEY: local-dev-webhook-key
RECOVERY_CHALLENGE_SECRET: e2e-recovery-secret-for-hmac-signing
CORS_ORIGINS: 'http://localhost:5174,http://localhost:4433'
AUTH_SCOPE_ENFORCEMENT: 'enforce'
RATE_LIMIT_GLOBAL_AUTH: '10000'
RATE_LIMIT_GLOBAL_ANON: '10000'
# Distinct from GLOBAL_AUTH so the read/write-split e2e can assert the read
# bucket's limit header differs from the mutation bucket's. High enough that
# read-heavy sibling suites never trip it (shared per-identity read bucket).
RATE_LIMIT_GLOBAL_READ: '7000'
RATE_LIMIT_EMBEDDING: '10000'
RATE_LIMIT_VOUCH: '10000'
RATE_LIMIT_SIGNING: '10000'
SIGNING_MAX_PENDING_REQUESTS: '10'
RATE_LIMIT_AGENT_KEY: '10000'
RATE_LIMIT_TASK_ARTIFACT_UPLOAD: '10000'
RATE_LIMIT_RECOVERY: '10000'
# High enough for the full suite's legitimate verification traffic. The
# adversarial rate-limit e2e seeds its isolated Redis counter immediately
# below this limit, proving a real shared-bucket 429 without poisoning
# sibling Ed25519 and previewSign tests.
RATE_LIMIT_PUBLIC_VERIFY: '10000'
RATE_LIMIT_PUBLIC_SEARCH: '10000'
RATE_LIMIT_LEGREFFIER_START: '10000'
RATE_LIMIT_REGISTRATION: '10000'
# Keep the pre-resolve IP throttle high: every suite shares the localhost
# IP, so a low value here would throttle unrelated suites mid-run.
RATE_LIMIT_PRE_RESOLVE_IP: '10000'
# Injected by e2e globalSetup after bootstrapping a sponsor genesis agent.
# Empty by default — server starts cleanly (503 on /public/legreffier/start)
# until globalSetup restarts with SPONSOR_AGENT_ID set.
SPONSOR_AGENT_ID: ${SPONSOR_AGENT_ID:-}
# Back the main rate limiter with the shared Redis store (Part 3). Exercises
# the Redis-backed path in e2e; without these the limiter is in-memory.
REDIS_HOST: redis
REDIS_PORT: '6379'
RUNTIME_SESSION_STORAGE_ENDPOINT: http://runtime-object-store:8333
RUNTIME_SESSION_STORAGE_REGION: auto
RUNTIME_SESSION_STORAGE_BUCKET: moltnet-runtime-sessions-e2e
RUNTIME_SESSION_STORAGE_ACCESS_KEY_ID: runtime-sessions
RUNTIME_SESSION_STORAGE_SECRET_ACCESS_KEY: runtime-sessions-secret
RUNTIME_SESSION_STORAGE_FORCE_PATH_STYLE: 'true'
RUNTIME_SESSION_MAX_BYTES: '10485760'
TASK_ARTIFACT_STORAGE_ENDPOINT: http://runtime-object-store:8333
TASK_ARTIFACT_STORAGE_REGION: auto
TASK_ARTIFACT_STORAGE_BUCKET: moltnet-task-artifacts-e2e
TASK_ARTIFACT_STORAGE_ACCESS_KEY_ID: runtime-sessions
TASK_ARTIFACT_STORAGE_SECRET_ACCESS_KEY: runtime-sessions-secret
TASK_ARTIFACT_STORAGE_FORCE_PATH_STYLE: 'true'
TASK_ARTIFACT_MAX_BYTES: '26214400'
depends_on:
app-db:
condition: service_healthy
app-db-migrate:
condition: service_completed_successfully
kratos:
condition: service_healthy
hydra:
condition: service_healthy
keto:
condition: service_healthy
talos:
# Talos auth is optional; REST startup must not block unrelated suites.
# Talos-specific e2e setup waits by calling its admin API directly.
condition: service_started
redis:
condition: service_healthy
runtime-object-store:
condition: service_started
healthcheck:
test:
[
'CMD',
'node',
'-e',
"fetch('http://localhost:8080/health').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))",
]
interval: 5s
timeout: 3s
retries: 15
start_period: 30s
console:
image: ${CONSOLE_IMAGE:-ghcr.io/getlarge/themoltnet/console:dev}
ports:
- '5174:80'
environment:
KRATOS_PUBLIC_URL: http://localhost:4433
API_BASE_URL: http://localhost:8080
CONSOLE_BASE_URL: http://localhost:5174
SIGNER_BASE_URL: http://127.0.0.1:17373
PACK_GC_COMPILE_TTL_DAYS: '7'
depends_on:
rest-api:
condition: service_healthy
kratos:
condition: service_healthy
mcp-server:
image: ${MCP_SERVER_IMAGE:-ghcr.io/getlarge/themoltnet/mcp-server:dev}
ports:
- '8001:8001'
environment:
NODE_ENV: production
PORT: '8001'
REST_API_URL: http://rest-api:8080
CONSOLE_BASE_URL: http://localhost:5174
AUTH_ENABLED: 'true'
ORY_PROJECT_URL: http://hydra:4444
CLIENT_CREDENTIALS_PROXY: 'true'
MCP_REDIS_HOST: redis
MCP_REDIS_PORT: '6379'
MCP_APP_DOMAIN: http://localhost:8001
MCP_APP_CONNECT_DOMAINS: http://localhost:8001,http://rest-api:8080
depends_on:
rest-api:
condition: service_healthy
hydra:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test:
[
'CMD',
'node',
'-e',
"fetch('http://localhost:8001/healthz').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))",
]
interval: 5s
timeout: 3s
retries: 15
start_period: 15s
mcp-host:
image: ${MCP_HOST_IMAGE:-ghcr.io/getlarge/themoltnet/mcp-host:dev}
ports:
- '8082:8080'
- '8083:8081'
environment:
AUTORUN: '0'
DEFAULT_ARGS: '{}'
DEFAULT_TOOL: tasks_app_open
MCP_SERVER_URL: http://localhost:8001/mcp
SANDBOX_BASE_URL: http://localhost:8083/sandbox.html
depends_on:
mcp-server:
condition: service_healthy
healthcheck:
test:
[
'CMD',
'node',
'-e',
"fetch('http://localhost:8080/healthz').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))",
]
interval: 5s
timeout: 3s
retries: 15
start_period: 15s