# ============================================================================= # FetchML Build System - Streamlined # ============================================================================= .PHONY: all build prod prod-with-native dev cross-platform build-cli \ native-build native-release native-debug native-test native-smoke native-clean \ clean clean-release prepare-release verify-build \ test test-unit test-integration test-e2e test-coverage \ test-infra-up test-infra-down \ lint configlint worker-configlint ci-local ci-checks \ verify-quick verify-all verify-schema test-schema-validation \ lint-custom verify-audit verify-audit-chain install-tools \ security-scan gosec govulncheck check-unsafe security-audit \ openapi-generate openapi-generate-server openapi-validate \ openapi-check-ci openapi-check-implementation \ openapi-generate-clients \ docs docs-setup docs-build docs-build-prod docs-generate docs-serve \ benchmark benchmark-local benchmark-native benchmark-compare \ load-test chaos-test profile-load profile-load-norate profile-ws-queue profile-tools detect-regressions detect-regressions-native \ clean-benchmarks status size complete-suite \ dev-up dev-down dev-logs dev-restart \ staging-up staging-down staging-logs staging-restart staging-status \ homelab-secure-up homelab-secure-down \ prod-up prod-down prod-logs prod-restart prod-status \ status-all clean-deploy rollback-staging rollback-prod deploy-health-check \ install docker-build dev-smoke prod-smoke test-auth help # ----------------------------------------------------------------------------- # Variables # ----------------------------------------------------------------------------- OK := ✓ DOCS_PORT ?= 1313 DOCS_BIND ?= 127.0.0.1 DOCS_BASEURL ?= / BUILD_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo dev) BUILD_TIME := $(shell date -u +%Y%m%d.%H%M%S) LDFLAGS := -X main.BuildHash=$(BUILD_HASH) -X main.BuildTime=$(BUILD_TIME) LDFLAGS_PROD := -s -w NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) DC := docker compose TEST_COMPOSE := deployments/docker-compose.test.yml define test_summary @passed=$$(grep -c "^--- PASS:" $(1) 2>/dev/null || echo 0); \ failed=$$(grep -c "^--- FAIL:" $(1) 2>/dev/null || echo 0); \ skipped=$$(grep -c "^--- SKIP:" $(1) 2>/dev/null || echo 0); \ echo " Passed: $$passed Failed: $$failed Skipped: $$skipped"; \ if [ "$$failed" -gt 0 ]; then exit 1; fi endef define ensure_tool @if ! command -v $(1) >/dev/null 2>&1; then \ echo "Installing $(1)..."; \ go install $(2); \ fi endef # ----------------------------------------------------------------------------- # Build # ----------------------------------------------------------------------------- all: build build: native-build openapi-generate-server @mkdir -p bin/server bin/cli bin/native go build -ldflags="$(LDFLAGS)" -o bin/server/api-server ./cmd/api-server/main.go go build -ldflags="$(LDFLAGS)" -o bin/server/worker ./cmd/worker/worker_server.go go build -ldflags="$(LDFLAGS)" -o bin/server/data_manager ./cmd/data_manager go build -ldflags="$(LDFLAGS)" -o bin/server/user_manager ./cmd/user_manager go build -ldflags="$(LDFLAGS)" -o bin/server/tui ./cmd/tui @cp native/build/lib*.so native/build/lib*.dylib bin/native/ 2>/dev/null || true $(MAKE) -C ./cli all @cp cli/zig-out/bin/ml bin/cli/ @echo "$(OK) All components built" prod: @mkdir -p bin/server bin/cli go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/api-server cmd/api-server/main.go go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/worker cmd/worker/worker_server.go go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/data_manager ./cmd/data_manager go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/user_manager ./cmd/user_manager go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/tui ./cmd/tui $(MAKE) -C cli prod @cp cli/zig-out/bin/ml bin/cli/ @echo "$(OK) Production binaries built" dev: @mkdir -p bin/server bin/cli go build -buildvcs=false -o bin/server/api-server cmd/api-server/main.go go build -buildvcs=false -o bin/server/worker cmd/worker/worker_server.go go build -buildvcs=false -o bin/server/data_manager ./cmd/data_manager go build -buildvcs=false -o bin/server/user_manager ./cmd/user_manager go build -buildvcs=false -o bin/server/tui ./cmd/tui $(MAKE) -C cli dev @cp cli/zig-out/bin/ml bin/cli/ @echo "$(OK) Development binaries built" native-build: @mkdir -p native/build @cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j$(NPROC) @echo "$(OK) Native libraries built" native-release: @mkdir -p native/build @cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="-O3 -DNDEBUG -fomit-frame-pointer" \ -DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -fomit-frame-pointer" && make -j$(NPROC) @echo "$(OK) Native libraries built (release)" native-debug: @mkdir -p native/build @cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON && make -j$(NPROC) @echo "$(OK) Native libraries built (debug + ASan)" native-test: native-build @cd native/build && ctest --output-on-failure @echo "$(OK) Native tests passed" native-smoke: @bash ./scripts/dev/smoke-test.sh --native @echo "$(OK) Native smoke test passed" native-clean: @rm -rf native/build @echo "$(OK) Native build cleaned" prod-with-native: native-release @mkdir -p bin/server bin/native @cp native/build/lib*.so native/build/lib*.dylib bin/native/ 2>/dev/null || true go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/api-server ./cmd/api-server/main.go go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/worker ./cmd/worker/worker_server.go @echo "$(OK) Production binaries built (with native libs)" cross-platform: @rm -rf dist && mkdir -p dist @echo "Building Linux x86_64 static binaries..." @for bin in \ "fetchml_api-server:cmd/api-server/main.go" \ "fetchml_worker:cmd/worker/worker_server.go" \ "fetchml_data_manager:./cmd/data_manager" \ "fetchml_user_manager:./cmd/user_manager" \ "fetchml_tui:./cmd/tui"; do \ name=$${bin%%:*}; src=$${bin##*:}; \ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false \ -ldflags="-s -w -buildid=" -o dist/$${name}_linux_amd64 $$src; \ done @echo "$(OK) Cross-platform binaries in dist/" build-cli: $(MAKE) -C cli all @echo "$(OK) CLI built" verify-build: @$(MAKE) build && shasum -a 256 bin/server/* bin/cli/* > /tmp/build_hash_1.txt 2>/dev/null || true @$(MAKE) build && shasum -a 256 bin/server/* bin/cli/* > /tmp/build_hash_2.txt 2>/dev/null || true @diff /tmp/build_hash_1.txt /tmp/build_hash_2.txt > /dev/null \ && echo "$(OK) Build is reproducible" \ || (echo "Build differs (expected with timestamps):"; diff /tmp/build_hash_1.txt /tmp/build_hash_2.txt || true) # ----------------------------------------------------------------------------- # Tests # ----------------------------------------------------------------------------- test: test-infra-up @[ -f bin/cli/ml ] || $(MAKE) build-cli @go test -v ./tests/unit/... ./tests/integration/... ./tests/e2e/... 2>&1 | grep -v "redis: connection pool" | tee /tmp/test-all.txt || true @echo "\n=== Test Summary ===" $(call test_summary,/tmp/test-all.txt) @$(MAKE) test-infra-down @cd cli && zig build test test-unit: @go test -v -short ./tests/unit/... 2>&1 | tee /tmp/test-unit.txt || true @echo "\n=== Unit Test Summary ===" $(call test_summary,/tmp/test-unit.txt) @cd cli && zig build test test-integration: test-infra-up @go test -v ./tests/integration/... 2>&1 | tee /tmp/test-integration.txt || true @echo "\n=== Integration Test Summary ===" $(call test_summary,/tmp/test-integration.txt) @$(MAKE) test-infra-down test-e2e: test-infra-up @[ -f bin/cli/ml ] || $(MAKE) build-cli @go test -v ./tests/e2e/... 2>&1 | tee /tmp/test-e2e.txt || true @echo "\n=== E2E Test Summary ===" $(call test_summary,/tmp/test-e2e.txt) @$(MAKE) test-infra-down test-coverage: @mkdir -p coverage go test -coverprofile=coverage/coverage.out ./... go tool cover -html=coverage/coverage.out -o coverage/coverage.html @echo "$(OK) Coverage report: coverage/coverage.html" test-infra-up: @echo "Starting test infrastructure..." @$(DC) -f $(TEST_COMPOSE) up -d @echo "$(OK) Test infrastructure started" test-infra-down: @$(DC) -f $(TEST_COMPOSE) down 2>/dev/null || true @echo "$(OK) Test infrastructure stopped" # ----------------------------------------------------------------------------- # Lint & Clean # ----------------------------------------------------------------------------- lint: gofmt -w ./cmd ./internal ./tests || true go vet ./... cd cli && zig fmt . @echo "$(OK) Lint complete" configlint: go run ./cmd/configlint --schema configs/schema/api_server_config.yaml \ configs/api/dev.yaml \ configs/api/homelab-secure.yaml \ configs/api/multi-user.yaml \ configs/api/prod.yaml worker-configlint: go run ./cmd/configlint --schema configs/schema/worker_config_schema.yaml \ configs/workers/worker-prod.toml \ configs/workers/docker.yaml \ configs/workers/docker-dev.yaml \ configs/workers/docker-prod.yaml \ configs/workers/homelab-secure.yaml ci-checks: @bash ./scripts/ci/checks.sh ci-local: lint configlint worker-configlint ci-checks test @mkdir -p coverage @echo "Running queue package tests with race detector..." go test -v -race -coverprofile=coverage/queue-coverage.out ./internal/queue/... $(MAKE) test-coverage clean: rm -rf bin/ coverage/ tests/bin/ dist/ rm -rf cli/zig-out/ cli/.zig-cache/ .zig-cache/ go clean @echo "$(OK) Cleaned" clean-release: clean rm -rf native/build/ go clean -cache -testcache find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true find . -name "*.pyc" -delete 2>/dev/null || true @./scripts/release/cleanup.sh testdata 2>/dev/null || true @./scripts/release/cleanup.sh logs 2>/dev/null || true @./scripts/release/cleanup.sh state 2>/dev/null || true @echo "$(OK) Release cleanup complete" prepare-release: clean-release @./scripts/release/verify.sh @echo "$(OK) Release preparation complete" # ----------------------------------------------------------------------------- # Verification # ----------------------------------------------------------------------------- verify-schema: @go test ./internal/manifest/... -run TestSchemaUnchanged -v @echo "$(OK) Schema validation passed" test-schema-validation: @go test ./internal/manifest/... -run TestSchemaValidatesExampleManifest -v @go test ./internal/manifest/... -run TestSchemaRejectsInvalidManifest -v @echo "$(OK) Schema tests passed" lint-custom: @mkdir -p bin/tools go build -ldflags="-s -w" -o bin/tools/fetchml-vet ./tools/fetchml-vet/cmd/fetchml-vet/ go vet -vettool=bin/tools/fetchml-vet ./internal/... ./cmd/... 2>/dev/null || true @echo "$(OK) Custom lint complete" verify-audit: @go test ./tests/unit/audit/... -run TestChainVerifier -v @echo "$(OK) Audit chain verification passed" verify-audit-chain: @if [ -z "$(AUDIT_LOG_PATH)" ]; then \ echo "Usage: make verify-audit-chain AUDIT_LOG_PATH=/path/to/audit.log"; exit 1; \ fi @mkdir -p bin/tools go build -ldflags="-s -w" -o bin/tools/audit-verifier ./cmd/audit-verifier/ ./bin/tools/audit-verifier -log-path=$(AUDIT_LOG_PATH) @echo "$(OK) Audit chain integrity verified" verify-quick: verify-schema verify-all: verify-schema test-schema-validation lint-custom verify-audit @echo "$(OK) All verification checks passed" # ----------------------------------------------------------------------------- # Security # ----------------------------------------------------------------------------- security-scan: gosec govulncheck check-unsafe @echo "$(OK) Security scan complete" gosec: $(call ensure_tool,gosec,github.com/securego/gosec/v2/cmd/gosec@latest) @mkdir -p reports gosec -fmt=json -out=reports/gosec-results.json ./... 2>/dev/null || true gosec -fmt=sarif -out=reports/gosec-results.sarif ./... 2>/dev/null || true gosec ./... 2>/dev/null || echo "Note: gosec found issues (see reports/gosec-results.json)" @echo "$(OK) gosec scan complete" govulncheck: $(call ensure_tool,govulncheck,golang.org/x/vuln/cmd/govulncheck@latest) govulncheck ./... @echo "$(OK) govulncheck complete" check-unsafe: @if grep -r "unsafe\." --include="*.go" ./internal ./cmd 2>/dev/null | grep -v "_test.go"; then \ echo "WARNING: unsafe package usage found — review required"; exit 1; \ else \ echo "$(OK) No unsafe package usage"; \ fi security-audit: security-scan @go test -v ./tests/security/... 2>/dev/null || echo "Note: No security tests yet" @echo "$(OK) Full security audit complete" # ----------------------------------------------------------------------------- # OpenAPI # ----------------------------------------------------------------------------- _ensure_oapi: $(call ensure_tool,oapi-codegen,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest) openapi-generate: _ensure_oapi oapi-codegen -package api -generate types api/openapi.yaml > internal/api/types.go @echo "$(OK) Generated internal/api/types.go" openapi-generate-server: _ensure_oapi oapi-codegen -package api -generate types,server api/openapi.yaml > internal/api/server_gen.go @echo "$(OK) Generated internal/api/server_gen.go" openapi-validate: @command -v openapi-generator >/dev/null 2>&1 \ && openapi-generator validate -i api/openapi.yaml 2>/dev/null \ || echo "Note: Install openapi-generator for validation" openapi-check-ci: openapi-generate @git diff --exit-code internal/api/types.go 2>/dev/null \ || (echo "ERROR: Run 'make openapi-generate' to sync" && exit 1) @echo "$(OK) OpenAPI types up to date" openapi-check-implementation: openapi-generate-server @git diff --exit-code internal/api/server_gen.go 2>/dev/null \ || (echo "ERROR: Run 'make openapi-generate-server' to sync" && exit 1) @echo "$(OK) Spec and implementation in sync" openapi-generate-clients: openapi-generate-ts openapi-generate-python @echo "$(OK) All client SDKs generated" openapi-generate-ts: @mkdir -p sdk/typescript @command -v npx >/dev/null 2>&1 || (echo "Note: npx not available" && exit 0) npx @openapitools/openapi-generator-cli generate \ -i api/openapi.yaml -g typescript-fetch -o sdk/typescript \ --additional-properties=supportsES6=true,npmName=fetchml-client 2>/dev/null \ || echo "Note: npm install -g @openapitools/openapi-generator-cli" openapi-generate-python: @mkdir -p sdk/python @command -v npx >/dev/null 2>&1 || (echo "Note: npx not available" && exit 0) npx @openapitools/openapi-generator-cli generate \ -i api/openapi.yaml -g python -o sdk/python \ --additional-properties=packageName=fetchml_client 2>/dev/null \ || echo "Note: npm install -g @openapitools/openapi-generator-cli" # ----------------------------------------------------------------------------- # Documentation # ----------------------------------------------------------------------------- docs-setup: @command -v hugo >/dev/null 2>&1 \ || (printf "Hugo not found.\n macOS: brew install hugo\n Linux: https://gohugo.io/installation/\n" && exit 1) @echo "$(OK) Hugo available" docs: docs-setup cd docs && hugo server --bind "$(DOCS_BIND)" --port "$(DOCS_PORT)" --baseURL "$(DOCS_BASEURL)" docs-build: cd docs && hugo docs-build-prod: cd docs && hugo --minify --baseURL "$(DOCS_PROD_BASEURL)" docs-generate: @mkdir -p docs/api @command -v npx >/dev/null 2>&1 \ && npx @redocly/cli build-docs api/openapi.yaml \ --output docs/api/index.html --title "FetchML API" 2>/dev/null \ || echo "Note: npm install -g @redocly/cli" docs-serve: @command -v npx >/dev/null 2>&1 \ && npx @redocly/cli preview-docs api/openapi.yaml \ || echo "Note: npx not available" # ----------------------------------------------------------------------------- # Performance # ----------------------------------------------------------------------------- benchmark: go test -bench=. -benchmem ./tests/benchmarks/... benchmark-local: @./scripts/benchmarks/run-benchmarks-local.sh benchmark-native: go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... benchmark-compare: @echo "=== Go ===" @go test -bench=. -benchmem ./tests/benchmarks/... 2>&1 \ | grep -E '(Benchmark|ns/op|allocs/op)' || true @echo "\n=== Native ===" @go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... 2>&1 \ | grep -E '(Benchmark|ns/op|allocs/op)' \ || echo "Native not available (run: make native-build)" load-test: go test -v ./tests/load/... chaos-test: go test -v ./tests/chaos/... profile-load: @mkdir -p tests/bin go test ./tests/load -run TestLoadProfile_Medium -count=1 -cpuprofile tests/bin/cpu_load.out @echo "$(OK) Profile → tests/bin/cpu_load.out" profile-load-norate: @mkdir -p tests/bin go test ./tests/load -run TestLoadProfile_Medium -count=1 \ -cpuprofile tests/bin/cpu_load.out -v -args -profile-norate profile-ws-queue: @mkdir -p tests/bin go test ./tests/integration -run WebSocketQueue -count=2 -cpuprofile tests/bin/cpu_ws.out @echo "$(OK) Profile → tests/bin/cpu_ws.out" profile-tools: @mkdir -p bin/tools go build -ldflags="-s -w" -o bin/tools/performance-regression-detector \ ./cmd/performance-regression-detector go build -ldflags="-s -w" -o bin/tools/profiler ./cmd/profiler @echo "$(OK) Profiling tools in bin/tools/" detect-regressions: profile-tools @mkdir -p tests/bin @if [ ! -f tests/bin/baseline.bench.txt ]; then \ echo "Creating baseline..."; \ go test -bench=. -benchmem ./tests/benchmarks/... | tee tests/bin/baseline.bench.txt; \ fi go test -bench=. -benchmem ./tests/benchmarks/... | tee tests/bin/current.bench.txt ./bin/tools/performance-regression-detector \ -baseline tests/bin/baseline.bench.txt \ -current tests/bin/current.bench.txt \ -threshold 10.0 detect-regressions-native: native-build profile-tools @mkdir -p tests/bin @if [ ! -f tests/bin/baseline-native.bench.txt ]; then \ echo "Creating native baseline..."; \ go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... \ | tee tests/bin/baseline-native.bench.txt; \ fi go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... \ | tee tests/bin/current-native.bench.txt ./bin/tools/performance-regression-detector \ -baseline tests/bin/baseline-native.bench.txt \ -current tests/bin/current-native.bench.txt \ -threshold 10.0 clean-benchmarks: @./scripts/maintenance/cleanup-benchmarks.sh benchmarks status: @./scripts/maintenance/cleanup-benchmarks.sh status size: @ls -lh bin/server/* bin/cli/* bin/tools/* 2>/dev/null || true complete-suite: benchmark load-test chaos-test profile-tools @echo "$(OK) Performance suite complete" # ----------------------------------------------------------------------------- # Deployment # ----------------------------------------------------------------------------- dev-up: $(DC) -f deployments/docker-compose.dev.yml up -d @echo "$(OK) Dev environment up (Caddy: 8080/8443 Redis: 6379 Prometheus: 9090 Grafana: 3000)" dev-down: $(DC) -f deployments/docker-compose.dev.yml down dev-logs: $(DC) -f deployments/docker-compose.dev.yml logs -f dev-restart: $(DC) -f deployments/docker-compose.dev.yml restart staging-up: @if [ ! -f deployments/.env.staging ]; then \ printf 'DATA_DIR=./data/staging\nLOG_LEVEL=info\nCOMPLIANCE_MODE=standard\n' \ > deployments/.env.staging; \ echo "Created deployments/.env.staging with defaults"; \ fi $(DC) -f deployments/docker-compose.staging.yml up -d staging-down: $(DC) -f deployments/docker-compose.staging.yml down staging-logs: $(DC) -f deployments/docker-compose.staging.yml logs -f staging-restart: $(DC) -f deployments/docker-compose.staging.yml restart staging-status: $(DC) -f deployments/docker-compose.staging.yml ps homelab-secure-up: $(DC) -f deployments/docker-compose.homelab-secure.yml up -d homelab-secure-down: $(DC) -f deployments/docker-compose.homelab-secure.yml down prod-up: @echo "⚠ WARNING: This is production. Ensure you have proper backups." @read -p "Continue? [y/N] " c && [ "$$c" = "y" ] || exit 1 $(DC) -f deployments/docker-compose.prod.yml up -d prod-down: $(DC) -f deployments/docker-compose.prod.yml down prod-logs: $(DC) -f deployments/docker-compose.prod.yml logs -f prod-restart: @read -p "Restart production? [y/N] " c && [ "$$c" = "y" ] || exit 1 $(DC) -f deployments/docker-compose.prod.yml restart prod-status: $(DC) -f deployments/docker-compose.prod.yml ps status-all: @for env in dev staging homelab-secure prod; do \ f="deployments/docker-compose.$$env.yml"; \ echo "=== $$env ==="; \ [ -f "$$f" ] && $(DC) -f "$$f" ps 2>/dev/null || echo "Not running"; \ echo; \ done clean-deploy: @echo "Removes all containers and volumes for every environment. Continue? [y/N]" @read -r c && [ "$$c" = "y" ] || exit 1 @for env in dev staging homelab-secure prod; do \ f="deployments/docker-compose.$$env.yml"; \ [ -f "$$f" ] && $(DC) -f "$$f" down -v 2>/dev/null || true; \ done docker system prune -f @echo "$(OK) All deployments cleaned" rollback-staging: @echo "⚠ Rolls back image only — queue state and audit log are NOT rolled back." @read -p "Continue? [y/N] " c && [ "$$c" = "y" ] || exit 1 $(DC) -f deployments/docker-compose.staging.yml down $(DC) -f deployments/docker-compose.staging.yml up -d @echo "$$(date -Iseconds) | rollback | staging | actor=$$(whoami)" \ >> deployments/.staging-audit.log rollback-prod: @echo "⚠ CRITICAL: Image rollback only." @echo " Queue state, audit chain, and storage artifacts are NOT rolled back." @read -p "CONFIRM PRODUCTION ROLLBACK? [yes/N] " c && [ "$$c" = "yes" ] || exit 1 $(DC) -f deployments/docker-compose.prod.yml down $(DC) -f deployments/docker-compose.prod.yml up -d @echo "$$(date -Iseconds) | rollback | prod | actor=$$(whoami)" \ >> deployments/.prod-audit.log @echo "$(OK) Rollback complete — verify: make prod-status" deploy-health-check: @echo "=== Health Checks ===" @for item in "Development=9101" "Staging=9102" "Production=9101"; do \ label=$${item%%=*}; port=$${item##*=}; \ printf "%-16s (localhost:$$port): " "$$label"; \ curl -fsS http://localhost:$$port/health 2>/dev/null && echo "✓" || echo "✗ not responding"; \ done # ----------------------------------------------------------------------------- # Install & Misc # ----------------------------------------------------------------------------- install: prod sudo cp bin/server/api-server /usr/local/bin/fetchml-api sudo cp bin/server/worker /usr/local/bin/fetchml-worker sudo cp bin/server/tui /usr/local/bin/fetchml-tui sudo cp bin/cli/ml /usr/local/bin/ml @echo "$(OK) Installed" docker-build: docker build -f build/docker/simple.Dockerfile -t fetchml:latest . @echo "$(OK) Docker image built" dev-smoke: @bash ./scripts/dev/smoke-test.sh dev prod-smoke: @bash ./scripts/dev/smoke-test.sh prod test-auth: @for role in admin researcher analyst; do \ echo "Testing $$role user..."; \ cp ~/.ml/config-$$role.toml ~/.ml/config.toml && ./bin/cli/ml status; \ done install-tools: $(call ensure_tool,gosec,github.com/securego/gosec/v2/cmd/gosec@latest) $(call ensure_tool,govulncheck,golang.org/x/vuln/cmd/govulncheck@latest) $(call ensure_tool,go-mutesting,github.com/zimmski/go-mutesting/cmd/go-mutesting@latest) $(call ensure_tool,scorecard,github.com/ossf/scorecard/v4/cmd/scorecard@latest) $(call ensure_tool,oapi-codegen,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest) @echo "$(OK) All tools installed" help: @printf "FetchML Build System\n\n" @printf "Build\n" @printf " build Build all components (default)\n" @printf " prod Production-optimized binaries\n" @printf " prod-with-native Production binaries + native C++ libs\n" @printf " dev Fast development build\n" @printf " cross-platform Linux x86_64 static binaries in dist/\n" @printf " build-cli Build Zig CLI only\n" @printf " clean Remove all build artifacts\n" @printf " clean-release Thorough pre-release cleanup\n" @printf " prepare-release clean-release + release verification\n" @printf " verify-build Check build reproducibility\n" @printf "\n" @printf "Native Libraries\n" @printf " native-build C++ libs (release)\n" @printf " native-release C++ libs (fully optimized)\n" @printf " native-debug C++ libs (debug + ASan)\n" @printf " native-test Run C++ unit tests\n" @printf " native-smoke C++ + Go integration smoke test\n" @printf " native-clean Remove native build artifacts\n" @printf "\n" @printf "Tests\n" @printf " test All tests with infrastructure (CI default)\n" @printf " test-unit Fast unit tests, no infrastructure\n" @printf " test-integration Integration tests (infra auto-managed)\n" @printf " test-e2e E2E tests (CLI auto-built, infra auto-managed)\n" @printf " test-coverage Generate HTML coverage report\n" @printf " test-infra-up Start Redis + SSH test containers\n" @printf " test-infra-down Stop test containers\n" @printf "\n" @printf "Lint & CI\n" @printf " lint gofmt + go vet + zig fmt\n" @printf " configlint Validate API YAML configs\n" @printf " worker-configlint Validate worker configs\n" @printf " ci-checks Maintainability checks\n" @printf " ci-local Full local CI (lint → config → test → coverage)\n" @printf "\n" @printf "Verification\n" @printf " verify-quick Schema check only\n" @printf " verify-all Schema + custom lint + audit chain\n" @printf " verify-audit-chain Verify live audit log AUDIT_LOG_PATH=...\n" @printf " install-tools Install all dev/CI tools in one shot\n" @printf "\n" @printf "Security\n" @printf " security-scan gosec + govulncheck + unsafe check\n" @printf " security-audit security-scan + security tests\n" @printf "\n" @printf "OpenAPI\n" @printf " openapi-generate Regenerate internal/api/types.go\n" @printf " openapi-generate-server Regenerate internal/api/server_gen.go\n" @printf " openapi-generate-clients TypeScript + Python SDKs\n" @printf " openapi-check-ci Fail if types.go out of sync\n" @printf " openapi-check-implementation Fail if server_gen.go out of sync\n" @printf "\n" @printf "Performance\n" @printf " benchmark Go benchmarks\n" @printf " benchmark-native Benchmarks with native libs\n" @printf " benchmark-compare Side-by-side Go vs native\n" @printf " load-test / chaos-test Load and chaos suites\n" @printf " detect-regressions Compare against saved baseline\n" @printf " complete-suite benchmark + load + chaos + profile tools\n" @printf "\n" @printf "Deployment\n" @printf " dev-up / dev-down Development environment\n" @printf " staging-up / staging-down Staging environment\n" @printf " prod-up / prod-down Production (confirmation required)\n" @printf " status-all Status across all environments\n" @printf " deploy-health-check HTTP health checks for all environments\n" @printf " rollback-staging Roll back staging image\n" @printf " rollback-prod Roll back production image (double-confirmed)\n" @printf " clean-deploy Tear down all environments + prune Docker\n" @printf "\n" @printf "Install\n" @printf " install Install binaries to /usr/local/bin\n" @printf " docker-build Build Docker image\n" @printf " install-tools Install all dev/CI tools\n" @printf " size Show binary sizes\n" @printf " help This message\n"