Services: - ja4sentinel: TLS/JA4 fingerprint capture daemon (Go, libpcap) - logcorrelator: JA4 log correlation engine (Go, ClickHouse) - mod_reqin_log: Apache module (C, JSON request logging) - bot_detector: ML bot detection pipeline (Python) - dashboard: FastAPI/Streamlit analytics UI (Python) Shared libraries: - shared/go/ja4common: logger, config, shutdown, ipfilter (Go module) - shared/python/ja4_common: ClickHouseClient, ClickHouseSettings (Python package) - shared/clickhouse/: canonical SQL migrations (10 files) Build & packaging: - Unified 3-stage Dockerfile.package for Go RPMs (el8/el9/el10) - go.work workspace linking sentinel, correlator, ja4common - Makefile with test-all, build-all, rpm-* targets Fixes applied: - go.work: 1.21 → 1.24.6 (required by sentinel) - correlator Dockerfiles: golang:1.21 → golang:1.24 - replace directives in go.mod for ja4common local path - pyproject.toml: setuptools.backends → setuptools.build_meta - Removed static libpcap linking (unavailable on Rocky 9) - Fixed data races in output/writers_test.go (sync.Mutex + atomic.Int32) - Rewrote corrupted test files (logger_test.go × 2) Test coverage: - correlator: 67.1% total (unixsocket 80.5%, config 91.7%, app 83.3%, multi 87.7%, stdout 100%) - sentinel: all 10 packages pass (api, capture, config, fingerprint, ipfilter, logging, output, tlsparse) Documentation: - README.md + docs/ (architecture, development, 5 services, shared libs, DB schema & migrations) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6.8 KiB
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
make build-all
This builds Docker images for:
ja4-platform/sentinel:latestja4-platform/correlator:latestja4-platform/bot-detector:latestja4-platform/dashboard:latest
mod-reqin-log is an Apache module and is only built as part of the RPM packaging process.
Building Individual Services
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
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
make rpm-all
Builds RPMs for sentinel, correlator, and mod-reqin-log targeting Rocky Linux 8/9/10:
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:
- Builder stage compiles the binary (Go) or shared object (C)
- RPM builder stage runs
rpmbuildfor each target distro (el8, el9, el10) - Output stage copies RPMs to the host via
--output type=local
Distribution Packages
make dist # Alias for rpm-all
# RPMs in services/<service>/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:
# 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)
# 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:
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
-
Create the service directory:
mkdir -p services/my-service/cmd/my-service mkdir -p services/my-service/internal -
Initialize the Go module:
cd services/my-service go mod init github.com/antitbone/ja4/my-service -
Add to
go.work:use ( ./services/sentinel ./services/correlator ./services/my-service # ← add this ./shared/go/ja4common ) -
Import the shared library:
import ( "github.com/antitbone/ja4/ja4common/logger" "github.com/antitbone/ja4/ja4common/config" "github.com/antitbone/ja4/ja4common/shutdown" ) -
Add Makefile targets:
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 -
Update
build-allandtest-alldependencies.
Python Service
- Create the service directory with a
requirements.txtorpyproject.toml. - Add
ja4-commonas a dependency (installed fromshared/python/ja4_common). - Use
from ja4_common.clickhouse import get_clientfor ClickHouse access. - 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:
go mod initin the service directory- Add the path to
go.work - Reference shared packages via their module path:
github.com/antitbone/ja4/ja4common/... - Run
go work syncto update the workspace
ja4_common Python Package
The shared Python package (shared/python/ja4_common) provides:
ClickHouseSettings— pydantic-settings model reading from.envClickHouseClient— singleton client with auto-reconnectget_client()— module-level singleton accessor
Extending ja4_common
- Add new modules under
shared/python/ja4_common/ja4_common/ - Export them in
__init__.py - Add dependencies to
pyproject.toml - 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:
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: