-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMakefile
More file actions
1537 lines (1399 loc) · 82.9 KB
/
Makefile
File metadata and controls
1537 lines (1399 loc) · 82.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
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
.PHONY: menu help setup configure deploy test test-local test-docker test-security mcp \
docker-up docker-up-prod docker-start docker-down docker-down-all docker-restart docker-restart-apis docker-restart-data docker-build docker-logs docker-ps docker-ps-all docker-clean docker-clean-all \
vault-generate-env vault-migrate vault-sync ssl-check \
github-check github-ensure \
install update manage login recover-admin rotate-secrets profile demo warmup demo-clean demo-status \
docker-deploy docker-deploy-infra docker-deploy-apis docker-deploy-llm docker-deploy-frontend \
deploy-user-app undeploy-user-app list-user-apps user-app-logs user-app-status \
mlx-status mlx-start mlx-stop mlx-restart mlx-media-status mlx-media-start mlx-media-start-all mlx-media-stop mlx-media-restart mlx-transcribe mlx-image host-agent-status host-agent-start host-agent-stop host-agent-restart \
build-images k8s-deploy k8s-sync k8s-build k8s-apply k8s-status k8s-delete k8s-secrets k8s-logs \
k8s-gpu-up k8s-gpu-down k8s-gpu-status k8s-gpu-window \
spot-check spot-swap spot-price \
connect disconnect k8s-connect-status \
build-manager \
busibox-build busibox
# Default target - interactive menu with health check
.DEFAULT_GOAL := menu
# ============================================================================
# VARIABLES
# ============================================================================
# Environment: development, demo, staging, production
# development - Docker dev mode (volume mounts, npm-linked busibox-app)
# demo - Docker prod mode (for demos/presentations)
# staging - Docker or Proxmox (10.96.201.x network)
# production - Docker or Proxmox (10.96.200.x network)
#
# Environment is read from the active deployment profile (.busibox/profiles.json)
# Falls back to development if no profile is configured
PROFILE_ENV := $(shell python3 -c "import json; d=json.load(open('.busibox/profiles.json')); p=d['profiles'][d['active']]; print(p['environment'])" 2>/dev/null)
ENV ?= $(if $(PROFILE_ENV),$(PROFILE_ENV),development)
# ============================================================================
# MANAGER CONTAINER
# ============================================================================
# When USE_MANAGER=1 (default), orchestration commands (install, manage, menu)
# run inside an ephemeral Docker container with guaranteed dependencies
# (Ansible, Docker CLI, vault tools, SSH). Set USE_MANAGER=0 to run directly
# on the host (legacy behavior, requires host-installed tools).
#
# Auto-detection: if Docker is not available, falls back to host execution.
DOCKER_AVAILABLE := $(shell docker info >/dev/null 2>&1 && echo 1 || echo 0)
USE_MANAGER ?= $(DOCKER_AVAILABLE)
# Manager runner script -- handles image build, volume mounts, vault files
MANAGER_RUN = bash scripts/make/manager-run.sh
MANAGER_RUN_IT = bash scripts/make/manager-run.sh --interactive
# Build the manager image (explicit rebuild)
build-manager:
@echo "Building manager container image..."
@docker build -t busibox-manager:latest -f provision/docker/manager.Dockerfile provision/docker
@echo "Manager image built."
# Service for targeted operations (comma-separated for multiple)
SERVICE ?=
# Action for service management (start, stop, restart, logs, redeploy, status)
ACTION ?=
# Inventory (maps to environment for Ansible)
# INV=staging maps to inventory/staging, INV=production maps to inventory/production
INV ?= staging
# Test mode: container (on deployed containers) or local (on your machine)
MODE ?= container
# Additional args (e.g., pytest args)
ARGS ?=
# Test listing options
CATEGORY ?=
DETAIL ?=
# Confirmation flag for destructive operations (milvus-reset)
CONFIRM ?=
# FAST mode: skip slow/gpu tests (default for local testing)
FAST ?=
# WORKER mode: start local data worker for integration tests
WORKER ?=
# Docker compose configuration
# Base: infrastructure and Python APIs
# Overlay selection based on environment:
# development -> COMPOSE_DEV (volume mounts, npm link)
# demo/staging/production -> COMPOSE_GITHUB (built from GitHub)
COMPOSE_FILE := docker-compose.yml
COMPOSE_DEV_MONOREPO := docker-compose.local-dev.yml
COMPOSE_GITHUB := docker-compose.github.yml
# Environment-prefixed files (allows multiple installations to coexist)
# ENV=demo -> .env.demo, .busibox-state-demo
# ENV=development -> .env.dev, .busibox-state-dev
# ENV=staging -> .env.staging, .busibox-state-staging
# ENV=production -> .env.prod, .busibox-state-prod
ENV_PREFIX = $(if $(filter demo,$(ENV)),demo,$(if $(filter development,$(ENV)),dev,$(if $(filter staging,$(ENV)),staging,$(if $(filter production,$(ENV)),prod,dev))))
ENV_FILE := .env.$(ENV_PREFIX)
STATE_FILE := .busibox-state-$(ENV_PREFIX)
# Read DEV_APPS_DIR from state file if it exists
# This is set via: make configure -> Docker Configuration -> Configure Dev Apps Directory
DEV_APPS_DIR := $(shell grep -s '^DEV_APPS_DIR=' $(STATE_FILE) 2>/dev/null | cut -d'=' -f2- | tr -d '"' || echo "")
export DEV_APPS_DIR
# Core Apps Mode: controls whether core-apps run with Turbopack hot-reload (dev) or
# as memory-efficient standalone builds (prod). Default is prod to minimize resource usage.
# Override via environment variable or toggle via: make manage SERVICE=core-apps (option 8)
# This is set via: make manage -> core-apps -> Switch mode (or CORE_APPS_MODE=dev make docker-up)
CORE_APPS_MODE ?= $(shell grep -s '^CORE_APPS_MODE=' $(STATE_FILE) 2>/dev/null | cut -d'=' -f2- | tr -d '"' || echo "prod")
export CORE_APPS_MODE
# Core Apps Source: always monorepo (busibox-frontend).
# Legacy separate repos are no longer supported.
CORE_APPS_SOURCE := monorepo
export CORE_APPS_SOURCE
# Host path for Docker volume mounts. The manager container mounts the repo
# at its real host path, so $(PWD) is always correct. BUSIBOX_HOST_PATH is
# also exported by manager-run.sh as a convenience.
BUSIBOX_HOST_PATH ?= $(PWD)
# Dev overlay always uses monorepo
COMPOSE_DEV = $(COMPOSE_DEV_MONOREPO)
# Automatically select overlay based on environment
# development uses dev overlay, everything else uses github overlay
COMPOSE_OVERLAY = $(if $(filter development,$(ENV)),$(COMPOSE_DEV),$(COMPOSE_GITHUB))
# ============================================================================
# DOCKER PROJECT NAMING
# ============================================================================
# Each environment gets its own isolated Docker project (stack) with prefixed containers:
# - demo-busibox -> demo-postgres, demo-authz-api, etc.
# - dev-busibox -> dev-postgres, dev-authz-api, etc.
# - staging-busibox -> staging-postgres, staging-authz-api, etc.
# - prod-busibox -> prod-postgres, prod-authz-api, etc.
#
# This allows multiple environments to coexist on the same Docker host.
# Map ENV to container prefix
CONTAINER_PREFIX = $(if $(filter demo,$(ENV)),demo,$(if $(filter development,$(ENV)),dev,$(if $(filter staging,$(ENV)),staging,$(if $(filter production,$(ENV)),prod,dev))))
# Compose project name (stack name)
COMPOSE_PROJECT = $(CONTAINER_PREFIX)-busibox
# Export for docker-compose and scripts
export COMPOSE_PROJECT_NAME = $(COMPOSE_PROJECT)
export CONTAINER_PREFIX
export BUSIBOX_ENV = $(ENV)
export GITHUB_AUTH_TOKEN
# ============================================================================
# MAIN MENU (Default)
# ============================================================================
# Interactive launcher menu - the main entry point
# Usage: make # Full interactive menu
# make ENV=staging # Start with staging environment selected
menu:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/launcher.sh
else
@bash scripts/make/launcher.sh
endif
# ============================================================================
# HELP
# ============================================================================
help:
@echo ""
@echo "╔══════════════════════════════════════════════════════════════════════╗"
@echo "║ Busibox Commands ║"
@echo "╚══════════════════════════════════════════════════════════════════════╝"
@echo ""
@echo "Usage: make <target> [OPTIONS]"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " MAIN COMMANDS"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " make # Interactive launcher menu"
@echo " make install # Fresh installation wizard"
@echo " make install SERVICE=authz # Deploy specific service (via Ansible)"
@echo " make manage # Service management (interactive)"
@echo " make login # Generate admin magic link + open browser"
@echo " make manage SERVICE=authz ACTION=restart # Direct service action"
@echo " CORE_APPS_MODE=prod make manage SERVICE=core-apps ACTION=restart # Prod mode"
@echo " make test # Testing menu"
@echo ""
@echo " Services: postgres, redis, minio, milvus, authz, agent, data,"
@echo " search, deploy, bridge, docs, embedding, litellm, core-apps, proxy, nginx"
@echo " Actions: start, stop, restart, logs, redeploy, status"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " OTHER COMMANDS"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " setup - Initial setup (install dependencies)"
@echo " configure - Configure models, GPUs, secrets"
@echo " deploy - Deploy services (via Ansible)"
@echo " milvus-reset - Drop + recreate Milvus collection (new embedding dim)"
@echo " mcp - Build MCP server for Cursor AI"
@echo " warmup - Check cache and download missing models"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " DOCKER DEVELOPMENT"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " Environment-based mode selection (ENV variable):"
@echo " make docker-up # Start (default: development)"
@echo " make docker-up ENV=development # Dev mode (volume mounts, npm link)"
@echo " make docker-up ENV=demo # Demo mode (prod-like, from GitHub)"
@echo " make docker-up SERVICE=busibox-portal # Start specific service"
@echo ""
@echo " Core Developer Mode (CORE_APPS_MODE, development ENV only):"
@echo " make docker-up # Default: prod mode (standalone, memory-efficient)"
@echo " CORE_APPS_MODE=dev make docker-up # Core developer mode (Turbopack hot-reload)"
@echo " make manage SERVICE=core-apps # Toggle mode interactively (options 8, 9)"
@echo ""
@echo " Core Apps Source:"
@echo " All core apps use the busibox-frontend monorepo"
@echo ""
@echo " Building:"
@echo " make docker-build # Build for current ENV"
@echo " make docker-build ENV=demo # Build prod-like images"
@echo " make docker-build SERVICE=authz-api # Build specific service"
@echo " make docker-build NO_CACHE=1 # Rebuild without cache"
@echo ""
@echo " Other:"
@echo " make docker-down # Stop all services"
@echo " make docker-restart # Restart all services"
@echo " make docker-ps # Show status"
@echo " make docker-logs # View all logs"
@echo " make docker-logs SERVICE=authz-api # View specific logs"
@echo " make docker-clean # Remove containers & data"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " VAULT & ENV MANAGEMENT"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " make vault-generate-env # Generate .env.local from vault"
@echo " make vault-migrate # Migrate .env.local to vault (one-time)"
@echo " make vault-sync # Sync vault with vault.example.yml"
@echo " make vault-setup # Multi-vault setup wizard"
@echo " make vault-setup ARGS='--status' # Show vault status"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " TESTING"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " Docker (local development):"
@echo " make test-docker # Show full help + filtering guide"
@echo " make test-docker SERVICE=agent # Run agent tests"
@echo " make test-docker SERVICE=agent ARGS='tests/unit' # Run only unit tests"
@echo " make test-docker SERVICE=agent ARGS='-k test_weather'"
@echo " make test-docker ACTION=list # List all services + test categories"
@echo " make test-docker ACTION=list SERVICE=agent CATEGORY=unit DETAIL=full"
@echo ""
@echo " Against remote (staging/production via Proxmox):"
@echo " make test-local SERVICE=agent INV=staging"
@echo " make test-local SERVICE=all INV=production"
@echo ""
@echo " On containers (via SSH):"
@echo " make test SERVICE=agent INV=staging"
@echo ""
@echo " Options:"
@echo " FAST=0 Include slow/GPU tests (default: FAST=1 skips them)"
@echo " WORKER=1 Start local data worker for pipeline tests"
@echo " ARGS='...' Pass pytest arguments"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " MLX & HOST-AGENT (Apple Silicon)"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " MLX Server (local LLM on Apple Silicon):"
@echo " make mlx-status # Check MLX server status"
@echo " make mlx-start # Start MLX server"
@echo " make mlx-stop # Stop MLX server"
@echo " make mlx-restart # Restart MLX server"
@echo " make mlx-media-status # Check MLX media server status"
@echo " make mlx-media-start # Start always-on media servers (voice/TTS only, ~0.2GB)"
@echo " make mlx-media-start-all # Start ALL media servers including on-demand"
@echo " make mlx-media-stop # Stop all media servers"
@echo " make mlx-media-restart # Restart always-on media servers"
@echo " make mlx-transcribe # Toggle Whisper STT server (on-demand, ~3GB)"
@echo " make mlx-image # Toggle Flux image-gen server (on-demand, ~4GB)"
@echo ""
@echo " Host Agent (controls MLX from Docker):"
@echo " make host-agent-status # Check host-agent status"
@echo " make host-agent-start # Start host-agent"
@echo " make host-agent-stop # Stop host-agent"
@echo " make host-agent-restart # Restart host-agent"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " KUBERNETES (Rackspace Spot)"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " make build-images # Trigger GHA image build (all services)"
@echo " make k8s-deploy # Apply + secrets + rollout restart"
@echo " make k8s-apply # Apply manifests only"
@echo " make k8s-secrets # Generate secrets from vault"
@echo " make k8s-status # Show deployment status"
@echo " make k8s-delete # Delete all resources"
@echo " make k8s-logs SERVICE=authz-api # View pod logs"
@echo ""
@echo " Access (HTTPS tunnel to K8s cluster):"
@echo " make connect # Connect (HTTPS tunnel + /etc/hosts)"
@echo " make connect DOMAIN=my.local # Custom domain"
@echo " make connect LOCAL_PORT=8443 # High port (no sudo)"
@echo " make disconnect # Tear down tunnel"
@echo " make k8s-connect-status # Check connection status"
@echo ""
@echo " GPU Burst (on-demand GPU for heavy AI):"
@echo " make k8s-gpu-up # Provision GPU + start vLLM"
@echo " make k8s-gpu-down # Stop vLLM + deprovision GPU"
@echo " make k8s-gpu-status # Show GPU burst status"
@echo " make k8s-gpu-window MINUTES=60 # Timed burst window"
@echo ""
@echo "═══════════════════════════════════════════════════════════════════════"
@echo " ENVIRONMENTS"
@echo "═══════════════════════════════════════════════════════════════════════"
@echo ""
@echo " development - Docker dev mode (volume mounts, npm-linked busibox-app)"
@echo " demo - Docker prod mode (apps from GitHub, for presentations)"
@echo " staging - 10.96.201.x network (Docker or Proxmox)"
@echo " production - 10.96.200.x network (Docker or Proxmox)"
@echo ""
@echo " development and demo are always Docker-only."
@echo " staging and production can use either Docker or Proxmox backends."
@echo " The interactive menu will ask for your preference."
@echo ""
# ============================================================================
# SETUP & CONFIGURE
# ============================================================================
setup:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/setup.sh
else
@bash scripts/make/setup.sh
endif
configure:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/configure.sh
else
@bash scripts/make/configure.sh
endif
# ============================================================================
# DEPLOY
# ============================================================================
# Interactive: make deploy
# Direct: make deploy SERVICE=authz INV=staging
deploy:
ifeq ($(USE_MANAGER),1)
ifdef SERVICE
@$(MANAGER_RUN) bash scripts/make/deploy.sh $(SERVICE) $(INV)
else
@$(MANAGER_RUN_IT) bash scripts/make/deploy.sh
endif
else
ifdef SERVICE
@bash scripts/make/deploy.sh $(SERVICE) $(INV)
else
@bash scripts/make/deploy.sh
endif
endif
# ============================================================================
# TESTING
# ============================================================================
# Run tests - interactive menu or direct service test
# Interactive: make test # Opens test menu
# Direct: make test SERVICE=authz INV=staging
test:
ifdef SERVICE
@PYTEST_ARGS="$(ARGS)" bash scripts/make/test.sh $(SERVICE) $(INV) $(MODE)
else
@bash scripts/make/test-menu.sh
endif
# Run tests locally against remote containers
# Usage: make test-local SERVICE=authz INV=staging
test-local:
ifndef SERVICE
@echo ""
@echo "Error: SERVICE is required"
@echo ""
@echo "Usage: make test-local SERVICE=<service> INV=<env>"
@echo ""
@echo "Services: authz, data, search, agent, all"
@echo "Environments: staging, production"
@echo ""
@echo "Examples:"
@echo " make test-local SERVICE=agent INV=staging"
@echo " make test-local SERVICE=all INV=production"
@echo " make test-local SERVICE=agent INV=staging ARGS='-k test_weather'"
@echo " make test-local SERVICE=data INV=staging WORKER=1"
@echo ""
@exit 1
endif
@FAST=$${FAST:-1} WORKER=$${WORKER:-0} bash scripts/test/run-local-tests.sh $(SERVICE) $(INV) $(ARGS)
# Bootstrap test databases (schema + OAuth clients + signing keys)
# Run this before running tests to initialize test_authz, test_data, test_agent
test-db-init:
@echo "Bootstrapping test databases..."
@docker compose -f docker-compose.local.yml --env-file .env.local run --rm test-db-init
# Check if test databases are bootstrapped
test-db-check:
@echo "Checking test database status..."
@docker exec local-postgres psql -U busibox_test_user -d test_authz -c "SELECT COUNT(*) as signing_keys FROM authz_signing_keys WHERE is_active = true;" 2>/dev/null || echo "Test databases not initialized. Run: make test-db-init"
# Run tests against local Docker
# Usage: make test-docker SERVICE=authz
# make test-docker ACTION=list # List all services + test categories
# make test-docker ACTION=list SERVICE=agent # List agent test files
# make test-docker ACTION=list SERVICE=agent CATEGORY=unit # List agent unit test files
# make test-docker ACTION=list SERVICE=agent CATEGORY=unit DETAIL=full # Collect test IDs from Docker
test-docker:
ifeq ($(ACTION),list)
@bash scripts/test/list-tests.sh $(SERVICE) $(CATEGORY) $(DETAIL)
else
ifndef SERVICE
@echo ""
@echo "make test-docker — Run pytest tests inside Docker containers"
@echo ""
@echo "USAGE:"
@echo " make test-docker SERVICE=<service> [ARGS='...'] [FAST=0|1]"
@echo ""
@echo "SERVICES (Python APIs — run via pytest inside Docker container):"
@echo " authz Authorization service (srv/authz)"
@echo " agent Agent/chat service (srv/agent)"
@echo " data Data service (srv/data)"
@echo " search Search service (srv/search)"
@echo " bridge Bridge service (srv/bridge)"
@echo ""
@echo "SERVICES (Node.js apps — run via vitest inside Docker container):"
@echo " busibox-portal Portal app"
@echo " busibox-agents Agents app"
@echo " apps Both Node.js apps"
@echo ""
@echo "SPECIAL:"
@echo " all Run all Python + Node.js tests"
@echo ""
@echo "FILTERING TESTS:"
@echo " Run a specific test directory:"
@echo " make test-docker SERVICE=agent ARGS='tests/unit'"
@echo " make test-docker SERVICE=agent ARGS='tests/integration'"
@echo ""
@echo " Run a specific test file:"
@echo " make test-docker SERVICE=agent ARGS='tests/unit/test_base_agent.py'"
@echo ""
@echo " Run a specific test class:"
@echo " make test-docker SERVICE=agent ARGS='tests/unit/test_base_agent.py::TestToolExecution'"
@echo ""
@echo " Run specific test methods (space-separated paths in ARGS):"
@echo " make test-docker SERVICE=agent ARGS='tests/unit/test_base_agent.py::TestToolExecution::test_execute_step_passes_ctx_when_tool_requires_it_without_scopes tests/unit/test_chat_optimization.py::test_generate_plan_backfills_required_query_for_document_search'"
@echo ""
@echo " Filter by test name pattern (-k):"
@echo " make test-docker SERVICE=agent ARGS='-k test_weather'"
@echo " make test-docker SERVICE=agent ARGS='-k \"test_chat and not slow\"'"
@echo ""
@echo " Filter by pytest marker (-m):"
@echo " make test-docker SERVICE=agent ARGS='-m integration'"
@echo " make test-docker SERVICE=agent ARGS='-m \"not slow and not gpu\"'"
@echo ""
@echo " Common markers: unit, integration, pvt, slow, gpu"
@echo ""
@echo "OPTIONS:"
@echo " FAST=1 Skip @pytest.mark.slow and @pytest.mark.gpu tests (default)"
@echo " FAST=0 Include slow/GPU tests"
@echo " WORKER=1 Start local data worker for pipeline tests"
@echo ""
@echo "DISCOVERING TESTS:"
@echo " make test-docker ACTION=list # Overview of all services"
@echo " make test-docker ACTION=list SERVICE=agent # List agent test files by category"
@echo " make test-docker ACTION=list SERVICE=agent CATEGORY=unit # List unit test files"
@echo " make test-docker ACTION=list SERVICE=agent CATEGORY=unit DETAIL=full"
@echo " # Collect full test IDs from Docker"
@echo ""
@exit 1
endif
@FAST=$${FAST:-1} INV=docker CONTAINER_PREFIX=dev bash scripts/test/run-local-tests.sh $(SERVICE) docker $(ARGS)
endif
# Security tests
test-security:
@bash tests/security/run_tests.sh
# ============================================================================
# MCP SERVER
# ============================================================================
mcp:
@MCP_BUILD=1 bash scripts/make/mcp.sh
# ============================================================================
# DOCKER LOCAL DEVELOPMENT
# ============================================================================
# Ensure .env.local exists
_ensure-env:
@if [ ! -f $(ENV_FILE) ]; then \
if [ -f env.local.example ]; then \
echo "Creating $(ENV_FILE) from env.local.example..."; \
cp env.local.example $(ENV_FILE); \
echo "Edit $(ENV_FILE) to add your API keys"; \
fi; \
fi
# Start Docker services based on environment
# ENV=development -> dev overlay (volume mounts, npm-linked busibox-app)
# ENV=demo/staging/production -> prod overlay (apps built from GitHub)
# Requires valid GitHub token for private repos
docker-up:
@echo "Starting Docker services (ENV=$(ENV), overlay=$(notdir $(COMPOSE_OVERLAY)))..."
@existing_id=$$(docker inspect -f '{{.Id}}' "$(CONTAINER_PREFIX)-user-apps" 2>/dev/null || true); \
if [ -n "$$existing_id" ]; then \
existing_status=$$(docker inspect -f '{{.State.Status}}' "$(CONTAINER_PREFIX)-user-apps" 2>/dev/null || echo "unknown"); \
existing_project=$$(docker inspect -f '{{ index .Config.Labels "com.docker.compose.project" }}' "$(CONTAINER_PREFIX)-user-apps" 2>/dev/null || echo ""); \
if [ "$$existing_status" != "running" ] || [ -n "$$existing_project" -a "$$existing_project" != "$(COMPOSE_PROJECT)" ]; then \
echo "[WARN] Removing stale container $(CONTAINER_PREFIX)-user-apps (status=$$existing_status, project=$$existing_project, expected=$(COMPOSE_PROJECT))"; \
docker rm -f "$(CONTAINER_PREFIX)-user-apps" >/dev/null 2>&1 || true; \
fi; \
fi
$(eval GITHUB_AUTH_TOKEN := $(or $(GITHUB_AUTH_TOKEN),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.github.personal_access_token 2>/dev/null || echo ""')))
$(eval POSTGRES_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.postgresql.password 2>/dev/null || (echo "FATAL: Cannot read POSTGRES_PASSWORD from vault" >&2 && exit 1)'))
$(eval MINIO_ACCESS_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_user 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_USER from vault" >&2 && exit 1)'))
$(eval MINIO_SECRET_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_password 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_PASSWORD from vault" >&2 && exit 1)'))
$(eval AUTHZ_MASTER_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.authz_master_key 2>/dev/null || (echo "FATAL: Cannot read AUTHZ_MASTER_KEY from vault" >&2 && exit 1)'))
$(eval LITELLM_API_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_api_key 2>/dev/null || echo ""'))
$(eval LITELLM_MASTER_KEY := $(or $(LITELLM_API_KEY),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_master_key 2>/dev/null || echo ""')))
$(eval LITELLM_SALT_KEY := $(or $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_salt_key 2>/dev/null || echo ""'),$(LITELLM_MASTER_KEY)))
$(eval NEO4J_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.neo4j.password 2>/dev/null || echo ""'))
@if [ -z "$(GITHUB_AUTH_TOKEN)" ]; then \
echo "[WARN] No GitHub token found (repos are public, continuing without it)"; \
fi
ifneq ($(DEV_APPS_DIR),)
@echo "Dev Apps Directory: $(DEV_APPS_DIR)"
endif
ifdef SERVICE
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" DEV_APPS_DIR="$(DEV_APPS_DIR)" BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d $(SERVICE)
else
@echo "Phase 1/3: starting infrastructure prerequisites..."
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" DEV_APPS_DIR="$(DEV_APPS_DIR)" BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d postgres redis minio etcd milvus neo4j
@echo "Phase 2/3: running one-time init services..."
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" DEV_APPS_DIR="$(DEV_APPS_DIR)" BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d minio-init milvus-init
@echo "Phase 3/3: starting remaining services..."
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" DEV_APPS_DIR="$(DEV_APPS_DIR)" BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d
endif
@echo ""
ifeq ($(ENV),development)
@echo "Development mode started. Use 'make docker-ps' to check status."
@echo "Core apps: busibox-frontend monorepo (7 apps)"
else
@echo "$(ENV) mode started. Use 'make docker-ps' to check status."
@echo "Next.js apps built from GitHub with npm-published busibox-app."
endif
# Legacy alias for explicit prod mode
docker-up-prod: _ensure-env
$(MAKE) docker-up ENV=demo
# Start Docker services without rebuilding (fast start)
docker-start:
@existing_id=$$(docker inspect -f '{{.Id}}' "$(CONTAINER_PREFIX)-user-apps" 2>/dev/null || true); \
if [ -n "$$existing_id" ]; then \
existing_status=$$(docker inspect -f '{{.State.Status}}' "$(CONTAINER_PREFIX)-user-apps" 2>/dev/null || echo "unknown"); \
existing_project=$$(docker inspect -f '{{ index .Config.Labels "com.docker.compose.project" }}' "$(CONTAINER_PREFIX)-user-apps" 2>/dev/null || echo ""); \
if [ "$$existing_status" != "running" ] || [ -n "$$existing_project" -a "$$existing_project" != "$(COMPOSE_PROJECT)" ]; then \
echo "[WARN] Removing stale container $(CONTAINER_PREFIX)-user-apps (status=$$existing_status, project=$$existing_project, expected=$(COMPOSE_PROJECT))"; \
docker rm -f "$(CONTAINER_PREFIX)-user-apps" >/dev/null 2>&1 || true; \
fi; \
fi
$(eval POSTGRES_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.postgresql.password 2>/dev/null || (echo "FATAL: Cannot read POSTGRES_PASSWORD from vault" >&2 && exit 1)'))
$(eval MINIO_ACCESS_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_user 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_USER from vault" >&2 && exit 1)'))
$(eval MINIO_SECRET_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_password 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_PASSWORD from vault" >&2 && exit 1)'))
$(eval AUTHZ_MASTER_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.authz_master_key 2>/dev/null || (echo "FATAL: Cannot read AUTHZ_MASTER_KEY from vault" >&2 && exit 1)'))
$(eval LITELLM_API_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_api_key 2>/dev/null || echo ""'))
$(eval LITELLM_MASTER_KEY := $(or $(LITELLM_API_KEY),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_master_key 2>/dev/null || echo ""')))
$(eval LITELLM_SALT_KEY := $(or $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_salt_key 2>/dev/null || echo ""'),$(LITELLM_MASTER_KEY)))
$(eval NEO4J_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.neo4j.password 2>/dev/null || echo ""'))
ifdef SERVICE
DEV_APPS_DIR="$(DEV_APPS_DIR)" BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d --no-build $(SERVICE)
else
DEV_APPS_DIR="$(DEV_APPS_DIR)" BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d --no-build
endif
@echo ""
@echo "Services started ($(ENV) mode). Use 'make docker-ps' to check status."
# Stop Docker services
# Uses COMPOSE_PROJECT_NAME to stop the correct environment's containers
# Usage: make docker-down ENV=demo # Stops demo-busibox stack
# make docker-down # Stops dev-busibox stack (default)
docker-down:
@echo "Stopping $(COMPOSE_PROJECT) containers..."
docker compose -p $(COMPOSE_PROJECT) down 2>/dev/null || \
(DEV_APPS_DIR="$(DEV_APPS_DIR)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) down 2>/dev/null || true)
# Stop ALL busibox environments (demo, dev, staging, prod)
docker-down-all:
@echo "Stopping all Busibox environments..."
docker compose -p demo-busibox down 2>/dev/null || true
docker compose -p dev-busibox down 2>/dev/null || true
docker compose -p staging-busibox down 2>/dev/null || true
docker compose -p prod-busibox down 2>/dev/null || true
# Restart Docker services (simple restart, no recreation)
docker-restart:
$(eval GITHUB_AUTH_TOKEN := $(or $(GITHUB_AUTH_TOKEN),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.github.personal_access_token 2>/dev/null || echo ""')))
$(eval POSTGRES_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.postgresql.password 2>/dev/null || (echo "FATAL: Cannot read POSTGRES_PASSWORD from vault" >&2 && exit 1)'))
$(eval MINIO_ACCESS_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_user 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_USER from vault" >&2 && exit 1)'))
$(eval MINIO_SECRET_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_password 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_PASSWORD from vault" >&2 && exit 1)'))
$(eval AUTHZ_MASTER_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.authz_master_key 2>/dev/null || (echo "FATAL: Cannot read AUTHZ_MASTER_KEY from vault" >&2 && exit 1)'))
$(eval LITELLM_API_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_api_key 2>/dev/null || echo ""'))
$(eval LITELLM_MASTER_KEY := $(or $(LITELLM_API_KEY),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_master_key 2>/dev/null || echo ""')))
$(eval LITELLM_SALT_KEY := $(or $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_salt_key 2>/dev/null || echo ""'),$(LITELLM_MASTER_KEY)))
$(eval NEO4J_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.neo4j.password 2>/dev/null || echo ""'))
ifdef SERVICE
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" DEV_APPS_DIR="$(DEV_APPS_DIR)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) restart $(SERVICE)
else
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" DEV_APPS_DIR="$(DEV_APPS_DIR)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) restart
endif
# Restart only API services (fast, preserves infrastructure like embedding-api, milvus, postgres)
# Use this when developing - embedding model stays loaded, so restarts are fast
docker-restart-apis:
@echo "Restarting API services (infrastructure tier preserved)..."
CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) restart authz-api deploy-api bridge-api data-api data-worker search-api agent-api docs-api proxy
# Restart data services only
docker-restart-data:
@echo "Restarting data services..."
CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) restart data-api data-worker
# Check/generate SSL certificates
ssl-check:
@if [ ! -f ssl/localhost.crt ] || [ ! -f ssl/localhost.key ]; then \
echo "[INFO] Generating SSL certificates..."; \
bash scripts/setup/generate-local-ssl.sh; \
fi
# Check GitHub token is available and valid
github-check:
@bash scripts/lib/github.sh check
$(eval GITHUB_AUTH_TOKEN := $(or $(GITHUB_AUTH_TOKEN),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.github.personal_access_token 2>/dev/null || echo ""')))
@if [ -n "$(GITHUB_AUTH_TOKEN)" ]; then \
export GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)"; \
fi
# Ensure GitHub token is available (interactive prompt if needed)
github-ensure:
@bash scripts/lib/github.sh ensure
$(eval GITHUB_AUTH_TOKEN := $(or $(GITHUB_AUTH_TOKEN),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.github.personal_access_token 2>/dev/null || echo ""')))
@if [ -n "$(GITHUB_AUTH_TOKEN)" ]; then \
export GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)"; \
fi
# Build Docker images based on environment
# ENV=development -> dev overlay, ENV=demo/staging/production -> prod overlay
# Requires valid GitHub token for private repos
docker-build: ssl-check
$(eval GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown"))
$(eval GITHUB_AUTH_TOKEN := $(or $(GITHUB_AUTH_TOKEN),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.github.personal_access_token 2>/dev/null || echo ""')))
$(eval POSTGRES_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.postgresql.password 2>/dev/null || (echo "FATAL: Cannot read POSTGRES_PASSWORD from vault" >&2 && exit 1)'))
$(eval MINIO_ACCESS_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_user 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_USER from vault" >&2 && exit 1)'))
$(eval MINIO_SECRET_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.minio.root_password 2>/dev/null || (echo "FATAL: Cannot read MINIO_ROOT_PASSWORD from vault" >&2 && exit 1)'))
$(eval AUTHZ_MASTER_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.authz_master_key 2>/dev/null || (echo "FATAL: Cannot read AUTHZ_MASTER_KEY from vault" >&2 && exit 1)'))
$(eval LITELLM_API_KEY := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_api_key 2>/dev/null || echo ""'))
$(eval LITELLM_MASTER_KEY := $(or $(LITELLM_API_KEY),$(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_master_key 2>/dev/null || echo ""')))
$(eval LITELLM_SALT_KEY := $(or $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.litellm_salt_key 2>/dev/null || echo ""'),$(LITELLM_MASTER_KEY)))
$(eval NEO4J_PASSWORD := $(shell bash -c 'source scripts/lib/vault.sh >/dev/null 2>&1 && set_vault_environment $(ENV_PREFIX) >/dev/null 2>&1 && ensure_vault_access >/dev/null 2>&1 && get_vault_secret secrets.neo4j.password 2>/dev/null || echo ""'))
@if [ -z "$(GITHUB_AUTH_TOKEN)" ]; then \
echo "[WARN] No GitHub token found (repos are public, continuing without it)"; \
fi
@echo "Building with version: $(GIT_COMMIT) (ENV=$(ENV), overlay=$(notdir $(COMPOSE_OVERLAY)))"
ifdef SERVICE
ifdef NO_CACHE
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" GIT_COMMIT=$(GIT_COMMIT) CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) build --no-cache $(SERVICE)
else
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" GIT_COMMIT=$(GIT_COMMIT) CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) build $(SERVICE)
endif
@echo "Recreating container to apply new image..."
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" GIT_COMMIT=$(GIT_COMMIT) BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d --no-deps $(SERVICE)
else
ifdef NO_CACHE
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" GIT_COMMIT=$(GIT_COMMIT) CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) build --no-cache
else
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" GIT_COMMIT=$(GIT_COMMIT) CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" LITELLM_SALT_KEY="$(LITELLM_SALT_KEY)" NEO4J_PASSWORD="$(NEO4J_PASSWORD)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) build
endif
@echo "Recreating containers to apply new images..."
GITHUB_AUTH_TOKEN="$(GITHUB_AUTH_TOKEN)" GIT_COMMIT=$(GIT_COMMIT) BUSIBOX_HOST_PATH="$(BUSIBOX_HOST_PATH)" CONTAINER_PREFIX=$(CONTAINER_PREFIX) COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT) POSTGRES_PASSWORD="$(POSTGRES_PASSWORD)" MINIO_ACCESS_KEY="$(MINIO_ACCESS_KEY)" MINIO_SECRET_KEY="$(MINIO_SECRET_KEY)" AUTHZ_MASTER_KEY="$(AUTHZ_MASTER_KEY)" LITELLM_API_KEY="$(LITELLM_API_KEY)" LITELLM_MASTER_KEY="$(LITELLM_MASTER_KEY)" docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) up -d
endif
# View Docker logs (uses environment-based overlay)
docker-logs:
ifdef SERVICE
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) logs -f $(SERVICE) 2>/dev/null || \
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_DEV) logs -f $(SERVICE) 2>/dev/null || \
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_PROD) logs -f $(SERVICE)
else
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) logs -f 2>/dev/null || \
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_DEV) logs -f 2>/dev/null || \
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_PROD) logs -f
endif
# Show Docker service status
# Usage: make docker-ps ENV=demo # Shows demo-busibox stack
# make docker-ps # Shows dev-busibox stack (default)
docker-ps:
@echo "Project: $(COMPOSE_PROJECT)"
@docker compose -p $(COMPOSE_PROJECT) ps 2>/dev/null || \
docker compose -f $(COMPOSE_FILE) -f $(COMPOSE_OVERLAY) ps 2>/dev/null
# Show status of ALL busibox environments
docker-ps-all:
@echo "=== Demo Environment ===" && docker compose -p demo-busibox ps 2>/dev/null || true
@echo ""
@echo "=== Development Environment ===" && docker compose -p dev-busibox ps 2>/dev/null || true
@echo ""
@echo "=== Staging Environment ===" && docker compose -p staging-busibox ps 2>/dev/null || true
@echo ""
@echo "=== Production Environment ===" && docker compose -p prod-busibox ps 2>/dev/null || true
# Clean Docker environment for current ENV
# Usage: make docker-clean ENV=demo # Cleans demo-busibox stack
docker-clean:
@echo "WARNING: This will remove $(COMPOSE_PROJECT) containers and volumes!"
@read -p "Are you sure? (y/N) " confirm; \
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
docker compose -p $(COMPOSE_PROJECT) down -v --remove-orphans 2>/dev/null || true; \
echo "Cleanup complete for $(COMPOSE_PROJECT)."; \
else \
echo "Cancelled."; \
fi
# Clean ALL busibox Docker environments
docker-clean-all:
@echo "WARNING: This will remove ALL Busibox environments (demo, dev, staging, prod)!"
@read -p "Are you sure? (y/N) " confirm; \
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
docker compose -p demo-busibox down -v --remove-orphans 2>/dev/null || true; \
docker compose -p dev-busibox down -v --remove-orphans 2>/dev/null || true; \
docker compose -p staging-busibox down -v --remove-orphans 2>/dev/null || true; \
docker compose -p prod-busibox down -v --remove-orphans 2>/dev/null || true; \
echo "All environments cleaned."; \
else \
echo "Cancelled."; \
fi
# ============================================================================
# INSTALLATION
# ============================================================================
# Unified install with interactive wizard or demo mode.
# All management after install is via web UI (Busibox Portal).
#
# Usage:
# make install # Full wizard
# make demo # Demo mode (auto-configure)
# make warmup # Check cache and download missing models
# make warmup FORCE=1 # Re-download (interactive selection)
# Interactive install with wizard OR deploy specific service
# Usage: make install # Install menu (Continue/Full/Clean if existing)
# make install VERBOSE=1 # Show all logs
# make install SERVICE=authz # Deploy specific service (uses Ansible)
# make install SERVICE=authz,agent # Deploy multiple services
#
# When called without SERVICE=, shows the same install options as `make` -> Install:
# - Fresh install if no existing installation
# - Continue/Full/Clean menu if existing installation detected
install:
ifeq ($(USE_MANAGER),1)
ifdef SERVICE
@$(MANAGER_RUN) bash scripts/make/service-deploy.sh "$(SERVICE)"
else
@USE_ANSIBLE_FOR_DOCKER=$(USE_ANSIBLE) $(MANAGER_RUN_IT) bash scripts/make/install-menu.sh $(if $(VERBOSE),-v)
endif
@if [ -f .mlx-setup-needed ]; then \
rm -f .mlx-setup-needed; \
echo "[INFO] Running MLX setup on macOS host..."; \
bash scripts/make/mlx-host-setup.sh; \
fi
@if [ -f .ssl-setup-needed ]; then \
rm -f .ssl-setup-needed; \
echo "[INFO] Running localhost SSL setup on host (mkcert if available)..."; \
bash scripts/setup/generate-local-ssl.sh; \
fi
@if [ -f .busibox-setup-link ]; then \
echo ""; \
echo "══════════════════════════════════════════════════════════════════════════════"; \
echo " Open the Busibox Portal to complete setup:"; \
echo ""; \
echo " $$(cat .busibox-setup-link)"; \
echo ""; \
echo "══════════════════════════════════════════════════════════════════════════════"; \
echo ""; \
rm -f .busibox-setup-link; \
fi
else
ifdef SERVICE
@bash scripts/make/service-deploy.sh "$(SERVICE)"
else
@USE_ANSIBLE_FOR_DOCKER=$(USE_ANSIBLE) bash scripts/make/install-menu.sh $(if $(VERBOSE),-v)
endif
endif
# DEPRECATED: Use 'make manage' for service management or 'make install SERVICE=x' to redeploy.
# Kept for backward compatibility - redirects to manage menu.
update:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/update-services.sh
else
@bash scripts/make/update-services.sh
endif
# Service management menu OR direct service action
# Interactive menu for stopping/starting/redeploying services
# Supports both Docker and Proxmox backends
#
# Usage: make manage # Interactive menu
# make manage SERVICE=authz ACTION=restart # Restart authz service
# make manage SERVICE=authz,agent ACTION=stop # Stop multiple services
# make manage SERVICE=authz ACTION=logs # View logs
#
# Core Developer Mode (Docker dev env only):
# make manage SERVICE=core-apps # Toggle via interactive menu (option 8, persisted to state)
# CORE_APPS_MODE=dev make manage SERVICE=core-apps ACTION=restart # Force dev mode (hot-reload)
# CORE_APPS_MODE=prod make manage SERVICE=core-apps ACTION=restart # Force prod mode (default)
#
# Actions: start, stop, restart, logs, redeploy, status
# For core-app redeploy, pass REF= to select a specific branch/tag:
# make manage SERVICE=busibox-portal ACTION=redeploy REF=v1.0.0
manage:
ifeq ($(USE_MANAGER),1)
ifdef SERVICE
@DEPLOY_REF="$(REF)" $(MANAGER_RUN) bash scripts/make/service-manage.sh "$(SERVICE)" "$(ACTION)"
else
@$(MANAGER_RUN_IT) bash scripts/make/manage.sh
endif
else
ifdef SERVICE
@DEPLOY_REF="$(REF)" bash scripts/make/service-manage.sh "$(SERVICE)" "$(ACTION)"
else
@bash scripts/make/manage.sh
endif
endif
# Reset Milvus collection (drop + recreate with correct embedding dimension)
# WARNING: Destroys all vectors — documents must be re-embedded afterward
# Usage: make milvus-reset # Interactive confirmation
# make milvus-reset CONFIRM=yes # Skip confirmation
milvus-reset:
ifeq ($(USE_MANAGER),1)
@CONFIRM="$(CONFIRM)" $(MANAGER_RUN_IT) bash scripts/make/milvus-reset.sh
else
@CONFIRM="$(CONFIRM)" bash scripts/make/milvus-reset.sh
endif
# Validate that container env vars match vault secrets
# Usage: make validate-env
validate-env:
@bash scripts/make/validate-env.sh
# Generate admin magic link and open browser
# Usage: make login
login:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/login.sh
else
@bash scripts/make/login.sh
endif
# Rotate secrets (interactive)
# Usage: make rotate-secrets
rotate-secrets:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/rotate-secrets.sh
else
@bash scripts/make/rotate-secrets.sh
endif
# Profile management (interactive)
# Usage: make profile
profile:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN_IT) bash scripts/make/launcher.sh --profile
else
@bash scripts/make/launcher.sh --profile
endif
# Generate recovery magic link for admin access
# Use when browser/passkey access is lost
recover-admin:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN) bash scripts/make/recover-admin.sh
else
@bash scripts/make/recover-admin.sh
endif
# ============================================================================
# ANSIBLE-BASED DOCKER DEPLOYMENT
# ============================================================================
# These targets use Ansible for Docker deployment, providing:
# - Idempotent operations
# - Unified patterns with LXC deployment
# - Better secrets management via Ansible Vault
#
# Usage: make docker-deploy # Full deployment via Ansible
# make docker-deploy-infra # Deploy infrastructure only
# make docker-deploy-apis # Deploy API services
# make docker-deploy-frontend # Deploy frontend apps
docker-deploy:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN) "cd provision/ansible && make docker CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)"
else
@cd provision/ansible && $(MAKE) docker CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)
endif
docker-deploy-infra:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN) "cd provision/ansible && make docker-infrastructure CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)"
else
@cd provision/ansible && $(MAKE) docker-infrastructure CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)
endif
docker-deploy-apis:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN) "cd provision/ansible && make docker-apis CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)"
else
@cd provision/ansible && $(MAKE) docker-apis CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)
endif
docker-deploy-llm:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN) "cd provision/ansible && make docker-llm CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)"
else
@cd provision/ansible && $(MAKE) docker-llm CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)
endif
docker-deploy-frontend:
ifeq ($(USE_MANAGER),1)
@$(MANAGER_RUN) "cd provision/ansible && make docker-frontend CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)"
else
@cd provision/ansible && $(MAKE) docker-frontend CONTAINER_PREFIX=$(CONTAINER_PREFIX) BUSIBOX_ENV=$(ENV)
endif
# ============================================================================
# USER APP DEPLOYMENT
# ============================================================================
# Deploy user/external applications to the user-apps container.
# These are untrusted apps that run in an isolated container.
#
# Usage:
# make deploy-user-app APP_ID=myapp REPO=owner/repo
# make deploy-user-app APP_ID=myapp REPO=owner/repo BRANCH=develop
# make deploy-user-app APP_ID=myapp REPO=owner/repo ENV=staging
# make undeploy-user-app APP_ID=myapp
#
# Variables:
# APP_ID - Unique identifier for the app (required)
# REPO - GitHub repository in owner/repo format (required for deploy)
# BRANCH - Branch to deploy (default: main)
# PORT - Port the app listens on (default: auto-assigned)
# ENV - Target environment: docker, staging, production
# App deployment variables
APP_ID ?=
REPO ?=
BRANCH ?= main
APP_PORT ?=
.PHONY: deploy-user-app undeploy-user-app list-user-apps user-app-logs user-app-status
deploy-user-app:
@if [ -z "$(APP_ID)" ]; then echo "ERROR: APP_ID is required"; exit 1; fi
@if [ -z "$(REPO)" ]; then echo "ERROR: REPO is required (format: owner/repo)"; exit 1; fi
@echo "Deploying user app: $(APP_ID) from $(REPO)"
@cd provision/ansible && ansible-playbook \
-i inventory/$(if $(filter docker,$(ENV)),docker,$(if $(filter staging production,$(ENV)),$(ENV),docker)) \
user-app-deploy.yml \
-e "app_id=$(APP_ID)" \
-e "github_repo=$(REPO)" \
-e "deploy_branch=$(BRANCH)" \
$(if $(APP_PORT),-e "app_port=$(APP_PORT)") \
$(if $(GITHUB_TOKEN),-e "github_token=$(GITHUB_TOKEN)") \
$(EXTRA_ARGS)
undeploy-user-app:
@if [ -z "$(APP_ID)" ]; then echo "ERROR: APP_ID is required"; exit 1; fi
@echo "Undeploying user app: $(APP_ID)"
@cd provision/ansible && ansible-playbook \
-i inventory/$(if $(filter docker,$(ENV)),docker,$(if $(filter staging production,$(ENV)),$(ENV),docker)) \
user-app-undeploy.yml \
-e "app_id=$(APP_ID)" \