-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile
More file actions
431 lines (394 loc) · 22.9 KB
/
Copy pathMakefile
File metadata and controls
431 lines (394 loc) · 22.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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# Nebu — Docker-only build system
# All build commands run inside Docker containers.
# No local Go, Elixir, or buf installation required.
DOCKER_GO = docker run --rm -v $(PWD):/workspace -w /workspace golang:1.26-alpine
DOCKER_ELIXIR = docker run --rm -v $(PWD):/workspace -w /workspace elixir:1.19-alpine
DOCKER_BUF = docker run --rm -v $(PWD):/workspace -w /workspace bufbuild/buf
DOCKER_NODE = docker run --rm -v $(PWD):/workspace -w /workspace node:22-alpine
DOCKER_TOFU = docker run --rm --entrypoint sh -v $(PWD):/workspace -w /workspace ghcr.io/opentofu/opentofu:1.9
DOCKER_HELM = docker run --rm --entrypoint sh -v $(PWD):/workspace -w /workspace alpine/helm:3.17
# Registry used for release images — override by setting CI_REGISTRY_IMAGE in the environment.
CI_REGISTRY_IMAGE ?= registry.gitlab.com/philippb/open-chat
# Strip the leading 'v' from TAG (e.g. v1.0.0 → 1.0.0) for image tagging.
IMAGE_VERSION = $(patsubst v%,%,$(TAG))
.PHONY: build-gateway build-core redeploy build-admin-css download-fonts download-vendor dev setup test-unit-go test-unit-elixir test-integration test-integration-elixir test-integration-ci test-e2e test-matrix-compat test-load-silber build-element-e2e test-e2e-element build-fluffychat-e2e test-e2e-fluffychat proto gen-api test-compose-ports test-compose-minio test-iac-validate test-load-syntax release release-push
## download-fonts: Download Inter + JetBrains Mono WOFF2 fonts (run once; commit results)
download-fonts:
docker run --rm -v $(PWD):/workspace -w /workspace alpine:3.19 sh -c "\
apk add -q --no-cache curl && \
mkdir -p gateway/internal/admin/static/fonts && \
curl -fsSL -o gateway/internal/admin/static/fonts/Inter-Regular.woff2 \
'https://fonts.bunny.net/inter/files/inter-latin-400-normal.woff2' && \
curl -fsSL -o gateway/internal/admin/static/fonts/Inter-Medium.woff2 \
'https://fonts.bunny.net/inter/files/inter-latin-500-normal.woff2' && \
curl -fsSL -o gateway/internal/admin/static/fonts/Inter-SemiBold.woff2 \
'https://fonts.bunny.net/inter/files/inter-latin-600-normal.woff2' && \
curl -fsSL -o gateway/internal/admin/static/fonts/JetBrainsMono-Regular.woff2 \
'https://fonts.bunny.net/jetbrains-mono/files/jetbrains-mono-latin-400-normal.woff2'"
## download-vendor: Download vendored JS files (run once; results are gitignored — downloaded at build time)
download-vendor:
@[ -f gateway/internal/admin/static/vendor/vue.esm-browser.prod.js ] || \
docker run --rm -v $(PWD):/workspace -w /workspace alpine:3.19 sh -c "\
apk add -q --no-cache curl && \
mkdir -p gateway/internal/admin/static/vendor && \
curl -fsSL -o gateway/internal/admin/static/vendor/vue.esm-browser.prod.js \
'https://cdn.jsdelivr.net/npm/vue@3.5.13/dist/vue.esm-browser.prod.js'"
## build-admin-css: Compile Tailwind CSS + DaisyUI into gateway/internal/admin/static/admin.css
build-admin-css:
$(DOCKER_NODE) sh -c "\
cd gateway/internal/admin && \
npm install --silent tailwindcss@3 daisyui@4 && \
npx tailwindcss \
--config tailwind.config.js \
--input tailwind.input.css \
--output static/admin.css \
--minify"
## build-gateway: Build the Go Gateway Docker image (multi-stage)
build-gateway: gen-api build-admin-css download-vendor
docker build -t nebu-gateway:dev ./gateway
## build-core: Compile the Elixir/OTP Core inside container (mix compile — does NOT rebuild the Docker image)
build-core:
$(DOCKER_ELIXIR) sh -c "cd core && mix local.hex --force && mix deps.get && mix compile"
## redeploy: Rebuild gateway + core + media Docker images (via docker compose) and restart containers.
## Use this after committing code changes — make build-gateway / make build-core do NOT update
## the images used by docker compose. Always use --no-cache to avoid stale layer reuse.
## Build args are computed here so deployed images always carry real version metadata.
redeploy:
GIT_COMMIT=$$(git rev-parse --short HEAD) \
BUILD_TIME=$$(date -u +%Y-%m-%dT%H:%M:%SZ) \
RELEASE_VERSION=$$(git describe --tags --always 2>/dev/null || echo dev) \
docker compose build --no-cache gateway core media
docker compose up -d --force-recreate gateway core media
## release: Build versioned release images locally (TAG=vN.N.N required).
## Images are tagged as $(CI_REGISTRY_IMAGE)/nebu-gateway:<version>, nebu-core:<version>, and nebu-media:<version>.
## Use docker login registry.gitlab.com before pushing. Chain with release-push:
## TAG=v1.0.0 make release release-push
## NOTE: Builds are sequential — if the gateway build fails, core/media are not built. Rerun make release to retry.
## NOTE: This target uses committed api_gen.go and admin.css as-is.
## Run 'make gen-api build-admin-css' first if openapi.yaml or Tailwind sources were changed.
release:
ifndef TAG
$(error TAG is required. Usage: TAG=v1.0.0 make release)
endif
ifeq ($(strip $(TAG)),)
$(error TAG is required. Usage: TAG=v1.0.0 make release)
endif
@echo "$(TAG)" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$$' || \
(echo "ERROR: TAG must match vN.N.N (e.g. v1.0.0). Got: $(TAG)" && exit 1)
docker build \
--build-arg GIT_COMMIT=$$(git rev-parse --short HEAD) \
--build-arg BUILD_TIME=$$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--build-arg RELEASE_VERSION=$(IMAGE_VERSION) \
-t $(CI_REGISTRY_IMAGE)/nebu-gateway:$(IMAGE_VERSION) \
./gateway
docker build \
--build-arg GIT_COMMIT=$$(git rev-parse --short HEAD) \
--build-arg BUILD_TIME=$$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--build-arg RELEASE_VERSION=$(IMAGE_VERSION) \
-t $(CI_REGISTRY_IMAGE)/nebu-core:$(IMAGE_VERSION) \
./core
docker build \
--build-arg GIT_COMMIT=$$(git rev-parse --short HEAD) \
--build-arg BUILD_TIME=$$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--build-arg RELEASE_VERSION=$(IMAGE_VERSION) \
-t $(CI_REGISTRY_IMAGE)/nebu-media:$(IMAGE_VERSION) \
./media
## release-push: Push versioned release images to the registry (TAG=vN.N.N required).
## Run after `make release TAG=vN.N.N`. Requires docker login registry.gitlab.com.
## Pushes nebu-gateway, nebu-core, and nebu-media images.
release-push:
ifndef TAG
$(error TAG is required. Usage: TAG=v1.0.0 make release-push)
endif
ifeq ($(strip $(TAG)),)
$(error TAG is required. Usage: TAG=v1.0.0 make release-push)
endif
docker push $(CI_REGISTRY_IMAGE)/nebu-gateway:$(IMAGE_VERSION)
docker push $(CI_REGISTRY_IMAGE)/nebu-core:$(IMAGE_VERSION)
docker push $(CI_REGISTRY_IMAGE)/nebu-media:$(IMAGE_VERSION)
## dev: Start the full local development stack (gateway, core, postgres, dex)
dev:
docker compose up
## setup: First-time setup — generate .secrets/internal_secret, MinIO credentials, and dev credentials
setup:
@mkdir -p .secrets
@if [ ! -f .secrets/internal_secret ]; then \
openssl rand -hex 32 > .secrets/internal_secret; \
echo "Generated .secrets/internal_secret"; \
else \
echo ".secrets/internal_secret already exists, skipping"; \
fi
@if [ ! -f .secrets/minio_root_user ]; then \
openssl rand -hex 16 > .secrets/minio_root_user; \
echo "Generated .secrets/minio_root_user"; \
else \
echo ".secrets/minio_root_user already exists, skipping"; \
fi
@if [ ! -f .secrets/minio_root_password ]; then \
openssl rand -hex 16 > .secrets/minio_root_password; \
echo "Generated .secrets/minio_root_password"; \
else \
echo ".secrets/minio_root_password already exists, skipping"; \
fi
@if [ ! -f .secrets/minio_app_access_key ]; then \
openssl rand -hex 16 > .secrets/minio_app_access_key; \
echo "Generated .secrets/minio_app_access_key"; \
else \
echo ".secrets/minio_app_access_key already exists, skipping"; \
fi
@if [ ! -f .secrets/minio_app_secret_key ]; then \
openssl rand -hex 16 > .secrets/minio_app_secret_key; \
echo "Generated .secrets/minio_app_secret_key"; \
else \
echo ".secrets/minio_app_secret_key already exists, skipping"; \
fi
@echo ""
@echo "WARNING: MinIO credentials in .secrets/ are for LOCAL DEVELOPMENT only."
@echo "Replace before first production start."
@echo ""
@echo "Dev credentials (Dex local users):"
@echo " kai@example.com / changeme (instance_admin)"
@echo " compliance@example.com / changeme (compliance_officer)"
@echo " alex@example.com / changeme (user)"
## test-unit-go: Run Go unit tests inside container
## Story 12.3: media module tests included (no race detector — CGO not required for media)
test-unit-go: download-vendor
$(DOCKER_GO) sh -c "apk add -q --no-cache gcc musl-dev && cd gateway && go test -race ./... && cd ../media && go test ./..."
## test-unit-elixir: Run Elixir unit tests inside container
test-unit-elixir:
$(DOCKER_ELIXIR) sh -c "cd core && mix local.hex --force && mix deps.get && mix test --warnings-as-errors"
## test-integration: Run full stack integration tests (Godog / Gherkin + Elixir integration tests).
## The Go test runner joins the nebu_default compose network so it can reach
## gateway:8080 and core:4000 by service name — works locally and in DinD CI.
## Elixir integration tests (mix test --include integration) also run against the live stack.
test-integration: setup
docker compose up -d --wait && \
docker run --rm -v $(PWD):/workspace -w /workspace \
--network=nebu_default \
-e NEBU_TEST_GATEWAY_URL=http://gateway:8080 \
-e NEBU_TEST_CORE_URL=http://core:4000 \
-e NEBU_TEST_DEX_URL=http://dex:5556 \
-e NEBU_TEST_MATRIX_URL=http://gateway:8008 \
-e NEBU_TEST_DB_URL=postgresql://nebu_app:nebu_app_dev_pw@postgres:5432/nebu \
-e NEBU_TEST_MIGRATION_DB_URL=postgresql://nebu_migrate:nebu_migrate_dev_pw@postgres:5432/nebu \
-e NEBU_TEST_CORE_GRPC_ADDR=core:9000 \
-e NEBU_TEST_INTERNAL_SECRET=$$(cat .secrets/internal_secret) \
golang:1.26-alpine \
sh -c "apk add -q --no-cache gcc musl-dev && cd gateway && go test -v -tags integration ./test/integration/..."; \
GO_EXIT=$$?; \
docker run --rm -v $(PWD):/workspace -w /workspace \
--network=nebu_default \
-e NEBU_DB_URL=postgresql://nebu_app:nebu_app_dev_pw@postgres:5432/nebu \
elixir:1.19-alpine \
sh -c "cd core && mix local.hex --force && mix deps.get && mix test --include integration --warnings-as-errors"; \
ELIXIR_EXIT=$$?; \
docker compose down; \
[ $$GO_EXIT -eq 0 ] && [ $$ELIXIR_EXIT -eq 0 ]
## test-integration-elixir: Run Elixir integration tests only (mix test --include integration).
## Requires the full stack to be running (docker compose up -d --wait).
## Connects to the nebu_default network to reach PostgreSQL at postgres:5432.
test-integration-elixir: setup
docker compose up -d --wait && \
docker run --rm -v $(PWD):/workspace -w /workspace \
--network=nebu_default \
-e NEBU_DB_URL=postgresql://nebu_app:nebu_app_dev_pw@postgres:5432/nebu \
elixir:1.19-alpine \
sh -c "cd core && mix local.hex --force && mix deps.get && mix test --include integration --warnings-as-errors"; \
EXIT=$$?; docker compose down; exit $$EXIT
## test-integration-ci: Run full stack integration tests using pre-built registry images (CI only).
## Requires CI_REGISTRY_IMAGE and CI_COMMIT_SHA to be set (injected automatically by GitLab CI).
## The caller must run `docker login` before invoking this target.
test-integration-ci: setup
docker compose -f docker-compose.yml -f docker-compose.ci.yml up -d --wait --no-build && \
docker run --rm -v $(PWD):/workspace -w /workspace \
--network=nebu_default \
-e NEBU_TEST_GATEWAY_URL=http://gateway:8080 \
-e NEBU_TEST_CORE_URL=http://core:4000 \
-e NEBU_TEST_DEX_URL=http://dex:5556 \
-e NEBU_TEST_MATRIX_URL=http://gateway:8008 \
-e NEBU_TEST_DB_URL=postgresql://nebu_app:nebu_app_dev_pw@postgres:5432/nebu \
-e NEBU_TEST_MIGRATION_DB_URL=postgresql://nebu_migrate:nebu_migrate_dev_pw@postgres:5432/nebu \
-e NEBU_TEST_CORE_GRPC_ADDR=core:9000 \
-e NEBU_TEST_INTERNAL_SECRET=$$(cat .secrets/internal_secret) \
golang:1.26-alpine \
sh -c "apk add -q --no-cache gcc musl-dev && cd gateway && go test -v -tags integration ./test/integration/..."; \
EXIT=$$?; docker compose -f docker-compose.yml -f docker-compose.ci.yml down; exit $$EXIT
## test-matrix-compat: Matrix SDK compatibility smoke test (optional CI gate — not part of test-integration)
## Validates that a real matrix-js-sdk client can connect, create a room, send a message, and
## receive it back via the room timeline. Requires the full stack to be running (docker compose up -d --wait).
test-matrix-compat:
docker compose up -d --wait && \
docker run --rm -v $(PWD):/workspace -w /workspace/tests/matrix_compat \
--network=nebu_default \
-e NEBU_MATRIX_URL=http://gateway:8008 \
-e NEBU_DEX_URL=http://dex:5556 \
node:22-alpine \
sh -c "npm ci && node smoke_test.js"
## test-load-silber: Silber-Tier load test — 500 concurrent VUs via k6 (optional gate — not part of test-integration)
## Requires: running stack (docker compose up -d --wait called automatically)
## Override: NEBU_LOAD_TARGET_URL=http://my-host:8008 make test-load-silber
test-load-silber:
docker compose up -d --wait && \
docker run --rm -v $(PWD)/tests/load:/scripts \
--network=nebu_default \
-e NEBU_LOAD_TARGET_URL=$${NEBU_LOAD_TARGET_URL:-http://gateway:8008} \
-e NEBU_DEX_URL=$${NEBU_DEX_URL:-http://dex:5556} \
grafana/k6:0.50.0 run /scripts/k6_chat.js
## test-e2e: Run all Playwright E2E tests (BDD + legacy) against a running stack.
## Requires: 127.0.0.1 dex in /etc/hosts for OIDC redirect flows
## Story 9-26 AC5: runs bddgen first, then all projects including element-web + admin-ui.
## Reset DB to bootstrap state first:
## docker compose exec postgres psql -U nebu -d nebu -c \
## "DELETE FROM server_config WHERE key IN ('bootstrap_completed','oidc_issuer','oidc_client_id','oidc_client_secret','instance_name');"
test-e2e:
cd e2e && \
npm install --silent && \
npx playwright install chromium --with-deps --quiet && \
npx bddgen && \
npx playwright test --reporter=list
## build-element-e2e: Build the Element Web E2E Docker image (uses official vectorim/element-web)
## Fast build (~5s) — no Rust/Flutter compilation required.
build-element-e2e:
docker build -t nebu-element-e2e:dev -f docker/Dockerfile.element-e2e .
## test-e2e-element: Run Element Web Browser-First BDD tests (story 9-26, Phase 2).
## Story 9-26 AC5: canonical target name (also aliased as test-e2e-element-bdd).
## Requires: stack running (`make dev`) + `127.0.0.1 dex` in /etc/hosts
test-e2e-element:
cd e2e && npm install --silent && \
npx playwright install chromium --with-deps --quiet && \
npx bddgen && \
npx playwright test --project=element-web --reporter=list
## test-e2e-element-legacy: Run old Element Web E2E tests (non-BDD, pre-story-9-26).
## Requires: stack running + element sidecar via --profile e2e.
test-e2e-element-legacy:
docker compose --profile e2e up -d --wait && \
cd e2e && npm install --silent && \
npx playwright install chromium --with-deps --quiet && \
npx playwright test tests/element_e2e.spec.ts; \
EXIT=$$?; exit $$EXIT
## test-e2e-admin: Run Admin UI BDD tests (story 9-26, Phase 3).
## Story 9-26 AC5: canonical target name (also aliased as test-e2e-admin-bdd).
## Requires: playwright-bdd installed + stack running
test-e2e-admin:
cd e2e && npm install --silent && \
npx playwright install chromium --with-deps --quiet && \
npx bddgen && \
npx playwright test --project=admin-ui --reporter=list
## build-fluffychat-e2e: Build the FluffyChat Web E2E Docker image (Flutter multi-stage — slow first build)
## Requires: tmp/fluffychat/ to contain the FluffyChat source checkout.
build-fluffychat-e2e:
docker build -t nebu-fluffychat-e2e:dev -f docker/Dockerfile.fluffychat-e2e .
## test-e2e-fluffychat: Run Playwright E2E tests against FluffyChat Web (real Matrix client)
## Requires: 127.0.0.1 dex in /etc/hosts (for SSO redirect via Dex)
## Starts full stack + fluffychat sidecar via --profile e2e.
## Does NOT run docker compose down after tests — leaves stack for debugging.
test-e2e-fluffychat:
docker compose --profile e2e up -d --wait && \
cd e2e && npm install --silent && \
npx playwright install chromium --with-deps --quiet && \
npx playwright test tests/fluffychat_e2e.spec.ts; \
EXIT=$$?; exit $$EXIT
## test-e2e-element-bdd: Alias for test-e2e-element (story 9-26 AC5 compatibility).
test-e2e-element-bdd: test-e2e-element
## test-e2e-admin-bdd: Alias for test-e2e-admin (story 9-26 AC5 compatibility).
test-e2e-admin-bdd: test-e2e-admin
## test-e2e-all: Alias for test-e2e (runs all BDD + legacy tests).
test-e2e-all: test-e2e
## test-compose-ports: CI smoke test — assert that port 9000 is NOT published by the core service.
## Story 5.29a AC8: gRPC port must not be bound to the host.
## Fallback for CI runners where the Go integration test cannot use Docker SDK.
test-compose-ports:
@echo "Checking that core service does NOT publish port 9000 to the host..."
@if docker compose config --format json 2>/dev/null | python3 -c \
"import json,sys; cfg=json.load(sys.stdin); ports=cfg.get('services',{}).get('core',{}).get('ports',[]); \
bound=[p for p in ports if str(p.get('target',''))==str(9000) and str(p.get('published','')) not in ('','0')]; \
sys.exit(1) if bound else print('PASS: port 9000 not published on host')"; then \
true; \
else \
echo "FAIL: core service still publishes port 9000 to the host. Remove '- \"9000:9000\"' from docker-compose.yml."; \
exit 1; \
fi
## test-compose-minio: CI smoke test — assert that MinIO service and secrets are configured correctly.
## Story 12.1 AC1+AC2: verifies minio service exists with minio_root_user + minio_root_password secrets.
## Story 12.3 AC2+AC3: verifies nebu-app IAM credentials present; createbuckets does NOT set public bucket policy.
test-compose-minio:
@echo "Checking MinIO service configuration in docker-compose.yml..."
@docker compose config --format json 2>/dev/null | python3 -c "\
import json,sys; cfg=json.load(sys.stdin); \
svc=cfg.get('services',{}); \
assert 'minio' in svc, 'FAIL: minio service missing from docker-compose.yml'; \
secrets=cfg.get('secrets',{}); \
assert 'minio_root_user' in secrets, 'FAIL: minio_root_user secret missing from docker-compose.yml'; \
assert 'minio_root_password' in secrets, 'FAIL: minio_root_password secret missing from docker-compose.yml'; \
assert 'minio_app_access_key' in secrets, 'FAIL: minio_app_access_key secret missing (Story 12.3 AC2)'; \
assert 'minio_app_secret_key' in secrets, 'FAIL: minio_app_secret_key secret missing (Story 12.3 AC2)'; \
ports=svc.get('minio',{}).get('ports',[]); \
targets=[str(p.get('target','')) for p in ports if isinstance(p,dict)]; \
assert '9000' in targets, 'FAIL: MinIO S3 API port 9000 not published'; \
assert '9001' in targets, 'FAIL: MinIO Console port 9001 not published'; \
cb_ep=svc.get('createbuckets',{}).get('entrypoint',''); \
ep_str=cb_ep if isinstance(cb_ep,str) else ' '.join(cb_ep); \
assert 'mc anonymous set' not in ep_str, 'FAIL: createbuckets entrypoint must NOT set public bucket policy (Story 12.3 AC3)'; \
print('PASS: MinIO service+secrets+IAM configured correctly; no public bucket policy (ports 9000+9001 published)')"
## proto: Generate gRPC stubs from .proto definitions (via buf + protoc)
## Step 1: buf generates Go stubs using remote plugins
## Step 2: protoc + protoc-gen-elixir generates Elixir stubs
proto:
docker run --rm -v $(PWD):/workspace -w /workspace/proto bufbuild/buf generate
docker run --rm -v $(PWD):/workspace -w /workspace/proto \
elixir:1.19-alpine sh -c '\
apk add -q --no-cache protobuf && \
mix local.hex --force --quiet && \
mix escript.install --force hex protobuf && \
mkdir -p ../core/apps/event_dispatcher/lib/pb && \
protoc --plugin=protoc-gen-elixir=/root/.mix/escripts/protoc-gen-elixir --elixir_out=../core/apps/event_dispatcher/lib/pb --proto_path=. core.proto'
## gen-api: Generate Go server stubs from openapi.yaml (oapi-codegen, strict-server)
gen-api:
$(DOCKER_GO) sh -c "go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest \
--config gateway/api/oapi-codegen.yaml \
gateway/api/openapi.yaml"
## test-iac-validate: Validate OpenTofu IaC files + Helm chart + k6 load test syntax.
## Runs tofu fmt -check (formatting) and tofu validate (syntax/types) for all example directories.
## Also runs helm lint and helm template on deploy/helm/nebu/ (Story 13-4a AC1+AC2, Story 13-4b AC3+AC5).
## If kubectl is available, runs helm template | kubectl apply --dry-run=client (Story 13-4c AC2).
## Also runs k6 inspect on load test scenarios and validates docker-compose.scale.yml (Story 13-5 AC1+AC3+AC4).
## No cloud credentials required — tofu validate checks syntax only, not provider resources.
## Story 13-1 AC3 + AC7, Story 13-4a AC1 + AC2, Story 13-4b AC3 + AC5, Story 13-4c AC3, Story 13-5 AC1+AC3+AC4: equivalent to the validate-iac CI job.
test-iac-validate: test-load-syntax
@echo "==> OpenTofu: fmt check (recursive)"
$(DOCKER_TOFU) -c "tofu fmt -check -recursive deploy/tofu/"
@echo "==> OpenTofu: validate deploy/tofu/examples/aws"
$(DOCKER_TOFU) -c "cd deploy/tofu/examples/aws && tofu init -backend=false && tofu validate"
@echo "==> OpenTofu: validate deploy/tofu/examples/stackit"
$(DOCKER_TOFU) -c "cd deploy/tofu/examples/stackit && tofu init -backend=false && tofu validate"
@echo "==> OpenTofu: validate deploy/tofu/examples/k8s"
$(DOCKER_TOFU) -c "cd deploy/tofu/examples/k8s && tofu init -backend=false && tofu validate"
@echo "==> Helm: lint deploy/helm/nebu/"
$(DOCKER_HELM) -c "helm lint deploy/helm/nebu/"
@echo "==> Helm: template render check deploy/helm/nebu/ (default values)"
$(DOCKER_HELM) -c "helm template nebu deploy/helm/nebu/ --set gateway.image.tag=validate --set core.image.tag=validate > /dev/null"
@echo "==> Helm: template render check deploy/helm/nebu/ (ingress + HPA enabled)"
$(DOCKER_HELM) -c "helm template nebu deploy/helm/nebu/ --set gateway.image.tag=validate --set core.image.tag=validate --set ingress.enabled=true --set ingress.hostname=nebu.example.com --set autoscaling.gateway.enabled=true > /dev/null"
@if command -v kubectl >/dev/null 2>&1 && kubectl get nodes -o name >/dev/null 2>&1; then \
echo "==> Helm: template dry-run: renders chart and validates against k8s API schema (requires kubectl in PATH)"; \
$(DOCKER_HELM) -c "helm template nebu deploy/helm/nebu/ \
-f deploy/helm/nebu/values-dev.yaml \
--set gateway.image.tag=validate \
--set core.image.tag=validate" \
| kubectl apply --dry-run=client -f -; \
else \
echo "==> Helm: no reachable cluster — skipping kubectl dry-run (run against a live kind cluster to enable)"; \
fi
@echo "==> IaC validation passed."
## test-load-syntax: Validate k6 load test scenario syntax and docker-compose.scale.yml config.
## Uses Docker-based k6 (no local k6 installation required).
## Story 13-5 AC1+AC3+AC4: syntax gate for gold-tier.js, silver-tier.js, and compose scale override.
## Runs: k6 inspect (syntax-only, no network, no VUs started) + docker compose config --quiet.
test-load-syntax:
@echo "==> k6: inspect k6/scenarios/gold-tier.js"
docker run --rm -v $(PWD)/k6:/scripts grafana/k6:0.55.0 inspect /scripts/scenarios/gold-tier.js
@echo "==> k6: inspect k6/scenarios/silver-tier.js"
docker run --rm -v $(PWD)/k6:/scripts grafana/k6:0.55.0 inspect /scripts/scenarios/silver-tier.js
@echo "==> Docker Compose: validate scale override config"
docker compose -f docker-compose.yml -f docker-compose.scale.yml config --quiet
@echo "==> Load test syntax validation passed."