# Development Guide This guide covers building, testing, packaging, and extending the ja4-platform monorepo. All build and test operations run inside Docker — no native Go, Python, or C toolchains are required on the host. ## Prerequisites | Requirement | Minimum Version | Notes | |-------------|----------------|-------| | Docker | 20.10+ | BuildKit enabled (`DOCKER_BUILDKIT=1`) | | Docker Compose | 2.x | For bot-detector and dashboard | | make | 3.81+ | GNU Make | | git | 2.x | For version tagging | No Go, Python, or C compilers are needed on the host machine. ## Building All Services ```bash make build-all ``` This builds Docker images for: - `ja4-platform/sentinel:latest` - `ja4-platform/correlator:latest` - `ja4-platform/bot-detector:latest` - `ja4-platform/dashboard:latest` mod-reqin-log is an Apache module and is only built as part of the RPM packaging process. ### Building Individual Services ```bash make build-sentinel # Go binary in Docker make build-correlator # Go binary in Docker make build-bot-detector # Python image make build-dashboard # FastAPI + React image ``` ## Running Tests ```bash make test-all ``` ### Per-Service Testing | Service | Command | Details | |---------|---------|---------| | sentinel | `make test-sentinel` | Go tests with `-race` flag, requires `NET_RAW`/`NET_ADMIN` caps | | correlator | `make test-correlator` | Go tests with 80% coverage gate enforced | | mod-reqin-log | `make test-mod-reqin-log` | C unit tests (JSON serialization, config parsing, header handling) | | bot-detector | `make test-bot-detector` | Python pytest suite | | dashboard | `make test-dashboard` | Python pytest for FastAPI routes | | ja4_common (Python) | `make test-ja4common-python` | Shared Python library tests | ## Building RPM Packages ```bash make rpm-all ``` Builds RPMs for sentinel, correlator, and mod-reqin-log targeting Rocky Linux 8/9/10: ```bash make rpm-sentinel # → services/sentinel/dist/rpm/ make rpm-correlator # → services/correlator/dist/rpm/ make rpm-mod-reqin-log # → services/mod-reqin-log/dist/rpm/ ``` Each RPM build uses a multi-stage Docker pipeline: 1. Builder stage compiles the binary (Go) or shared object (C) 2. RPM builder stage runs `rpmbuild` for each target distro (el8, el9, el10) 3. Output stage copies RPMs to the host via `--output type=local` ### Distribution Packages ```bash make dist # Alias for rpm-all # RPMs in services//dist/rpm/el{8,9,10}/ ``` ## Local Development Workflow ### Go Services (sentinel, correlator) The `go.work` workspace links Go modules: ``` go 1.21 use ( ./services/sentinel ./services/correlator ./shared/go/ja4common ) ``` If you have Go 1.21+ installed locally, you can develop without Docker: ```bash # Run sentinel tests locally cd services/sentinel && go test ./... -race -v # Run correlator tests locally cd services/correlator && go test ./... -race -cover -v # Build sentinel binary locally (requires libpcap-dev) cd services/sentinel && go build -o ja4sentinel ./cmd/ja4sentinel/ ``` ### Python Services (bot-detector, dashboard) ```bash # Install shared library in development mode cd shared/python/ja4_common && pip install -e . # Run bot-detector locally cd services/bot-detector && pip install -r bot_detector/requirements.txt python -m bot_detector.bot_detector # Run dashboard locally cd services/dashboard && pip install -r backend/requirements.txt uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000 ``` ### C Module (mod-reqin-log) Requires `apxs` (Apache extension tool) and development headers: ```bash cd services/mod-reqin-log make build # Compiles mod_reqin_log.so make test # Runs unit tests make rpm # Builds RPM packages ``` ## Adding a New Service ### Go Service 1. Create the service directory: ```bash mkdir -p services/my-service/cmd/my-service mkdir -p services/my-service/internal ``` 2. Initialize the Go module: ```bash cd services/my-service go mod init github.com/antitbone/ja4/my-service ``` 3. Add to `go.work`: ``` use ( ./services/sentinel ./services/correlator ./services/my-service # ← add this ./shared/go/ja4common ) ``` 4. Import the shared library: ```go import ( "github.com/antitbone/ja4/ja4common/logger" "github.com/antitbone/ja4/ja4common/config" "github.com/antitbone/ja4/ja4common/shutdown" ) ``` 5. Add Makefile targets: ```makefile build-my-service: docker build -f services/my-service/Dockerfile -t ja4-platform/my-service:latest . test-my-service: docker build -f services/my-service/Dockerfile.dev -t ja4-platform/my-service-tests:latest . docker run --rm ja4-platform/my-service-tests:latest ``` 6. Update `build-all` and `test-all` dependencies. ### Python Service 1. Create the service directory with a `requirements.txt` or `pyproject.toml`. 2. Add `ja4-common` as a dependency (installed from `shared/python/ja4_common`). 3. Use `from ja4_common.clickhouse import get_client` for ClickHouse access. 4. Add Makefile targets following the bot-detector/dashboard pattern. ## go.work Workspace The `go.work` file at the repository root links all Go modules, allowing cross-module development without publishing: ``` go 1.21 use ( ./services/sentinel ./services/correlator ./shared/go/ja4common ) ``` When adding a new Go module: 1. `go mod init` in the service directory 2. Add the path to `go.work` 3. Reference shared packages via their module path: `github.com/antitbone/ja4/ja4common/...` 4. Run `go work sync` to update the workspace ## ja4_common Python Package The shared Python package (`shared/python/ja4_common`) provides: - `ClickHouseSettings` — pydantic-settings model reading from `.env` - `ClickHouseClient` — singleton client with auto-reconnect - `get_client()` — module-level singleton accessor ### Extending ja4_common 1. Add new modules under `shared/python/ja4_common/ja4_common/` 2. Export them in `__init__.py` 3. Add dependencies to `pyproject.toml` 4. Run tests: `make test-ja4common-python` ### Using in a New Service Add to `requirements.txt`: ``` ja4-common @ file:///app/shared/python/ja4_common ``` Or in Docker, copy the shared library and install: ```dockerfile COPY shared/python/ja4_common /app/shared/python/ja4_common RUN pip install /app/shared/python/ja4_common ``` ## Environment Variables Each service reads configuration from environment variables and/or YAML config files. See individual service documentation for the full reference: - [Sentinel configuration](services/sentinel.md#configuration-reference) - [Correlator configuration](services/correlator.md#configuration-reference) - [Bot Detector configuration](services/bot-detector.md#environment-variables) - [Dashboard configuration](services/dashboard.md#configuration)