fetch_ml/Makefile
Jeremie Fraeys 537faa6825
build: streamline Makefile from 1000+ to ~730 lines
- Replace bloated 1016-line Makefile with focused 730-line version
- Add DC := docker compose variable for v2 compatibility
- Consolidate 5 install-* targets into single install-tools
- Remove redundant targets: self-cleanup, test-full, deploy-up/down/status
- Add missing implementations for all 85 declared .PHONY targets
- Include native lib variants, verification, security, OpenAPI, docs, perf targets
2026-03-04 13:22:21 -05:00

714 lines
28 KiB
Makefile

# =============================================================================
# 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"