Skip to content

Commit 24757fb

Browse files
authored
kafSIEM Ontology / Unmanned Systems (Drones) pack / Critical Infrastructure (SCADA) pack
This branch completes the ops-ontology / AgentOps foundation work for kafSIEM. It moves AgentOps off the old JSON snapshot path onto a SQLite-backed runtime and typed analyst API, adds graph and pack primitives for operations-focused ontology workflows, replaces the legacy desk with the new runtime investigation UI, and documents the new Operations / Fusion product surface with demo support and screenshots.
2 parents b85cfe9 + 20f0444 commit 24757fb

148 files changed

Lines changed: 18049 additions & 2183 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ AGENTOPS_TLS_INSECURE_SKIP_VERIFY=false
6161
AGENTOPS_POLICY_PATH=/config/agentops_policy.yaml
6262
AGENTOPS_REPLAY_ENABLED=true
6363
AGENTOPS_REPLAY_PREFIX=kafsiem-agentops-replay
64-
AGENTOPS_OUTPUT_PATH=public/agentops-state.json
64+
AGENTOPS_OUTPUT_PATH=public/agentops.db
6565

6666
# UI operating mode.
6767
UI_MODE=OSINT

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ node_modules/
55
dist/
66
dist-ssr/
77
coverage/
8+
*.lcov
89
.tmp/
910
/kafsiem-collector
1011
cmd/test-*/
@@ -58,6 +59,18 @@ internal/collector/run/public/
5859

5960
# Tool caches
6061
.eslintcache
62+
.cache/
63+
.vite/
64+
.vite-inspect/
65+
.turbo/
66+
.parcel-cache/
67+
.next/
68+
.nuxt/
69+
.svelte-kit/
70+
storybook-static/
71+
playwright-report/
72+
test-results/
73+
junit.xml
6174
.npm/
6275
.pnpm-store/
6376
.yarn/

.spectral.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
extends:
2+
- spectral:oas

Dockerfile.collector

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ ARG TARGETARCH
99

1010
COPY go.mod go.sum ./
1111
RUN go mod download
12+
COPY api ./api
1213
COPY cmd ./cmd
1314
COPY internal ./internal
15+
COPY packs ./packs
1416
COPY registry ./registry
1517
COPY public ./public
1618

1719
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -o /out/kafsiem-collector ./cmd/kafsiem-collector
20+
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -o /out/kafsiem-api ./cmd/kafsiem-api
1821

1922
FROM alpine:3.20 AS geonames
2023
RUN apk add --no-cache curl unzip
@@ -31,8 +34,20 @@ WORKDIR /app
3134
COPY --from=build /out/kafsiem-collector /usr/local/bin/kafsiem-collector
3235
COPY --from=geonames /tmp/cities500.txt ./registry/cities500.txt
3336
COPY registry ./registry
37+
COPY packs /packs
3438
COPY docker/collector-entrypoint.sh /usr/local/bin/collector-entrypoint.sh
3539

3640
RUN chmod +x /usr/local/bin/collector-entrypoint.sh
3741

3842
ENTRYPOINT ["/usr/local/bin/collector-entrypoint.sh"]
43+
44+
FROM alpine:3.20 AS api-runtime
45+
46+
RUN apk add --no-cache ca-certificates
47+
48+
WORKDIR /app
49+
50+
COPY --from=build /out/kafsiem-api /usr/local/bin/kafsiem-api
51+
COPY packs /packs
52+
53+
ENTRYPOINT ["/usr/local/bin/kafsiem-api"]

Makefile

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ CODEQL_GO_OUT ?= $(CODEQL_DIR)/go.sarif
2222
BRANCH ?= main
2323
RELEASE_LEVEL ?= patch
2424

25-
.PHONY: help check check-commit install clean lint typecheck test build ci \
25+
.PHONY: help check check-commit install clean lint typecheck test build ci api-lint pack-lint pack-docs \
2626
npm-install-if-needed \
2727
go-fmt go-fmt-check go-test go-race go-cover go-vet go-codeql commit-check \
2828
docker-build docker-up docker-down docker-logs docker-shell \
29-
dev-start dev-stop dev-stop-clean dev-restart dev-restart-clean dev-logs dev-ensure-env \
29+
dev-start dev-start-collector dev-start-api dev-stop dev-stop-clean dev-restart dev-restart-clean dev-logs dev-ensure-env \
3030
code-ql code-ql-summary \
3131
release-patch release-minor release-major \
3232
branch-protection
@@ -84,7 +84,18 @@ test: ## Run repository test suite
8484
build: ## Build the production bundle
8585
npm run build
8686

87-
ci: check lint test build ## Run the full local CI suite
87+
api-lint: ## Lint OpenAPI with Spectral
88+
npx --yes @stoplight/spectral-cli lint --fail-severity=error api/openapi.yaml
89+
90+
pack-lint: ## Validate bundled packs
91+
@mkdir -p $(GOCACHE_DIR) $(GOMODCACHE_DIR)
92+
GOCACHE=$(GOCACHE_DIR) GOMODCACHE=$(GOMODCACHE_DIR) go run ./cmd/kafsiem-api --validate-packs --packs ./packs
93+
94+
pack-docs: ## Generate bundled pack reference docs
95+
@mkdir -p $(GOCACHE_DIR) $(GOMODCACHE_DIR)
96+
GOCACHE=$(GOCACHE_DIR) GOMODCACHE=$(GOMODCACHE_DIR) go run ./cmd/pack-docs --packs ./packs --out docs/packs
97+
98+
ci: check lint typecheck test build go-test api-lint pack-lint ## Run the full local CI suite
8899

89100
go-fmt: ## Auto-format Go code
90101
@mkdir -p $(GOCACHE_DIR) $(GOMODCACHE_DIR)
@@ -146,10 +157,17 @@ dev-ensure-env: ## Ensure local .env contains API_BEARER_TOKEN for local API pro
146157

147158
dev-start: registry/cities500.txt dev-collector-bin dev-ensure-env ## Start the local HTTP dev stack on localhost
148159
docker build -f Dockerfile.collector.dev -t kafsiem-collector:dev .
149-
$(DOCKER_COMPOSE) build kafsiem
160+
$(DOCKER_COMPOSE) build kafsiem kafsiem-api
150161
KAFSIEM_COLLECTOR_IMAGE=kafsiem-collector:dev $(DOCKER_COMPOSE) up -d --no-build
151162
@echo "kafSIEM available at http://localhost:$${KAFSIEM_HTTP_PORT:-8080}"
152-
@open "http://localhost:$${KAFSIEM_HTTP_PORT:-8080}"
163+
164+
dev-start-collector: registry/cities500.txt dev-collector-bin dev-ensure-env ## Start only the collector-side services
165+
docker build -f Dockerfile.collector.dev -t kafsiem-collector:dev .
166+
KAFSIEM_COLLECTOR_IMAGE=kafsiem-collector:dev $(DOCKER_COMPOSE) up -d --no-build browser collector
167+
168+
dev-start-api: dev-ensure-env ## Start the API and web surfaces for debugging
169+
$(DOCKER_COMPOSE) build kafsiem-api kafsiem
170+
$(DOCKER_COMPOSE) up -d --no-build kafsiem-api kafsiem
153171

154172
dev-stop: ## Stop the local dev stack, remove volumes, prune dangling images
155173
$(DOCKER_COMPOSE) down --remove-orphans -v
@@ -163,20 +181,18 @@ dev-stop-clean: ## Stop stack, remove feed-data volume, and aggressively prune D
163181
dev-restart: registry/cities500.txt dev-collector-bin dev-ensure-env ## Restart the local dev stack (removes volumes, rebuilds)
164182
$(DOCKER_COMPOSE) down --remove-orphans -v
165183
docker build -f Dockerfile.collector.dev -t kafsiem-collector:dev .
166-
$(DOCKER_COMPOSE) build kafsiem
184+
$(DOCKER_COMPOSE) build kafsiem kafsiem-api
167185
KAFSIEM_COLLECTOR_IMAGE=kafsiem-collector:dev $(DOCKER_COMPOSE) up -d --no-build
168186
@echo "kafSIEM available at http://localhost:$${KAFSIEM_HTTP_PORT:-8080}"
169-
@open "http://localhost:$${KAFSIEM_HTTP_PORT:-8080}"
170187

171188
dev-restart-clean: registry/cities500.txt dev-collector-bin dev-ensure-env ## Restart from scratch (removes volumes, prunes caches)
172189
$(DOCKER_COMPOSE) down --remove-orphans -v
173190
@docker image prune -af >/dev/null 2>&1 || true
174191
@docker builder prune -af >/dev/null 2>&1 || true
175192
docker build --no-cache -f Dockerfile.collector.dev -t kafsiem-collector:dev .
176-
$(DOCKER_COMPOSE) build --no-cache kafsiem
193+
$(DOCKER_COMPOSE) build --no-cache kafsiem kafsiem-api
177194
KAFSIEM_COLLECTOR_IMAGE=kafsiem-collector:dev $(DOCKER_COMPOSE) up -d --no-build
178195
@echo "kafSIEM available at http://localhost:$${KAFSIEM_HTTP_PORT:-8080}"
179-
@open "http://localhost:$${KAFSIEM_HTTP_PORT:-8080}"
180196

181197
dev-sync-registry: ## Merge source_registry.json into the running DB (adds new feeds)
182198
$(DOCKER_COMPOSE) exec collector kafsiem-collector --source-db /data/sources.db --curated-seed /app/registry/source_registry.json --source-db-merge-registry

README.md

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,74 @@
11
# kafSIEM
22

3-
kafSIEM is the open-source edition of our OSINT pipeline, used across multiple installations and packaged for local and server deployment.
3+
kafSIEM is an open-source operations and fusion analysis surface. It turns
4+
Kafka-observed operational traffic and selected OSINT context into an
5+
auditable entity graph for analyst workflows.
46

5-
It now ships with two distinct operating surfaces:
7+
The product can run standalone for teams that need a local, Docker-first
8+
analysis stack. It can also complement existing enterprise intelligence
9+
platforms through typed APIs, pack-defined ontology, provenance-preserving
10+
records, and exportable graph context.
11+
12+
It now ships with three operating modes:
613

714
- `OSINT`: the existing globe-first external intelligence workflow
8-
- `AgentOps`: Kafka-backed flow tracking for KafClaw agent communication
9-
- `HYBRID`: AgentOps plus selective external OSINT context
15+
- `Operations`: Kafka-backed flow tracking and internal operational workflows
16+
- `Fusion`: operations plus selective external OSINT context
1017

1118
This repository has been prepared for public use by removing non-public, internal, and protected source integrations while keeping the operational pipeline structure intact.
1219

20+
## Screenshots
21+
22+
<p align="center">
23+
<a href="public/images/Scalytics-OSINT-Prediction.png">
24+
<img src="public/images/Scalytics-OSINT-Prediction.png" alt="kafSIEM OSINT mode screenshot" width="32%" />
25+
</a>
26+
<a href="public/images/Scalytics-Ontology-Drones.png">
27+
<img src="public/images/Scalytics-Ontology-Drones.png" alt="kafSIEM Operations ontology drones screenshot" width="32%" />
28+
</a>
29+
<a href="public/images/Scalytics-Ontology-SCADA.png">
30+
<img src="public/images/Scalytics-Ontology-SCADA.png" alt="kafSIEM Operations ontology SCADA screenshot" width="32%" />
31+
</a>
32+
</p>
33+
<p align="center">
34+
<strong>OSINT</strong> | <strong>Operations / Drones</strong> | <strong>Operations / SCADA</strong>
35+
</p>
36+
1337
## Open-Source Scope
1438

1539
- Public-ready OSINT pipeline architecture
16-
- AgentOps flow tracking over Kafka for KafClaw-style agent traffic
40+
- Operations flow tracking over Kafka for KafClaw-style agent traffic
41+
- Entity, edge, provenance, map, and timeline APIs backed by SQLite
42+
- Pack-defined ontology for unmanned systems and SCADA / critical infrastructure workflows
1743
- Docker-first deployment for reproducible installs
18-
- Web dashboard + Go collector runtime
44+
- Web dashboard, Go collector runtime, and standalone analyst API service
1945
- Configurable ingestion and refresh cadence
2046

47+
## Target Deployments
48+
49+
kafSIEM is designed for two initial operations profiles:
50+
51+
- unmanned systems teams that need readiness, sortie, EW, software, and
52+
signoff evidence connected across fleet activity
53+
- SCADA and critical infrastructure teams that need plant, device, change,
54+
alarm, firmware, vulnerability, and session evidence connected across
55+
operational telemetry
56+
57+
These profiles are shipped as data packs under `packs/`. The active pack
58+
contract is documented in [docs/packs/drones.md](https://github.com/scalytics/kafSIEM/blob/main/docs/packs/drones.md)
59+
and [docs/packs/scada.md](https://github.com/scalytics/kafSIEM/blob/main/docs/packs/scada.md).
60+
2161
## Operating Modes
2262

2363
The runtime mode is driven by environment and mounted policy files.
2464

2565
- `UI_MODE=OSINT` keeps the existing OSINT product behavior.
26-
- `UI_MODE=AGENTOPS` switches the desktop UI to the AgentOps flow desk.
27-
- `UI_MODE=HYBRID` keeps AgentOps primary and adds selective external-intel context.
66+
- `UI_MODE=AGENTOPS` switches the desktop UI to the Operations desk.
67+
- `UI_MODE=HYBRID` switches the desktop UI to Fusion mode with selective external-intel context.
68+
69+
Current runtime values remain `OSINT`, `AGENTOPS`, and `HYBRID` for
70+
compatibility. User-facing product naming is `OSINT`, `Operations`, and
71+
`Fusion`.
2872

2973
AgentOps is a separate bounded domain in the codebase:
3074

@@ -33,6 +77,8 @@ AgentOps is a separate bounded domain in the codebase:
3377

3478
It is not implemented as a generic plugin tree.
3579

80+
Architecture details live in [docs/architecture.md](https://github.com/scalytics/kafSIEM/blob/main/docs/architecture.md).
81+
3682
## Run With Docker
3783

3884
```bash
@@ -54,13 +100,19 @@ make dev-restart
54100
make dev-logs
55101
```
56102

57-
For a local AgentOps demo with mocked Kafka-derived traffic and the real dashboard:
103+
The old JSON-backed AgentOps demo UI has been removed. Operations and Fusion
104+
development uses the live runtime desk against `kafsiem-api` and the
105+
collector-written SQLite store. For UI-only demos without Kafka or SQLite,
106+
the same runtime desk can run against typed mock streams:
58107

59108
```bash
60-
npm run demo:agentops
109+
npm run demo:ontology
110+
npm run demo:fusion
61111
```
62112

63-
This opens the desktop UI directly in `AgentOps` mode via `/?demo=agentops`, serves demo state from `public/demo/*.json`, and mocks the replay endpoint locally.
113+
These open `/?demo=ontology` and `/?demo=fusion`, which keep OSINT untouched
114+
and feed the Operations/Fusion ontology dashboard through mocked typed API
115+
resources.
64116

65117
## Remote Install (wget bootstrap)
66118

@@ -71,17 +123,17 @@ wget -qO- https://raw.githubusercontent.com/scalytics/kafSIEM/main/deploy/instal
71123
The installer will:
72124
- verify Docker + Compose availability
73125
- clone or update the repo on the host
74-
- ask for the operating profile (`OSINT`, `AGENTOPS`, or `HYBRID`)
126+
- ask for the operating profile (`OSINT`, `Operations`, or `Fusion`)
75127
- set GHCR runtime images (`ghcr.io/scalytics/kafsiem-web` + `ghcr.io/scalytics/kafsiem-collector`)
76128
- prompt for install mode (`preserve` or `fresh` volume reset)
77129
- prompt for the common site setting (`KAFSIEM_SITE_ADDRESS`)
78130
- when domain mode is enabled, optionally check `ufw`/`firewalld` and validate local 80/443 availability
79131
- prompt only for the profile-relevant runtime keys
80132
- optionally run `docker compose pull` and start with `--no-build`
81133

82-
- The release pipeline builds two images: a web image and a Go collector image.
134+
- The release pipeline builds three images: a web image, a Go collector image, and a Go analyst API image.
83135
- The scheduled feed refresh workflow runs the Go collector.
84-
- The web image uses Caddy, with collector output mounted into the web container at runtime.
136+
- The web image uses Caddy, with collector output mounted into the web container at runtime and `/api/*` reverse-proxied to the standalone analyst API service.
85137
- In Docker dev mode, the collector initializes empty JSON outputs on a fresh volume and writes live output on the first successful run.
86138

87139
## Run Locally Without Docker
@@ -117,11 +169,11 @@ The installer is profile-driven and only asks for the settings that matter for t
117169
- prompts for `KAFSIEM_SITE_ADDRESS`
118170
- prompts for OSINT credentials and optional LLM toggles
119171
- writes `UI_MODE=OSINT` and `PROFILE=osint-default`
120-
- `AGENTOPS`
172+
- `Operations`
121173
- prompts for `KAFSIEM_SITE_ADDRESS`
122174
- prompts for AgentOps Kafka brokers, auth mode, group identifiers, topic mode, replay, and optional reject mirroring
123175
- writes `UI_MODE=AGENTOPS` and `PROFILE=agentops-default`
124-
- `HYBRID`
176+
- `Fusion`
125177
- prompts for both the OSINT and AgentOps settings above
126178
- writes `UI_MODE=HYBRID` and `PROFILE=hybrid-ops`
127179

@@ -137,16 +189,18 @@ AgentOps-specific runtime knobs include:
137189
- `AGENTOPS_REPLAY_ENABLED`
138190
- `AGENTOPS_REJECT_TOPIC`
139191
- `AGENTOPS_OUTPUT_PATH`
192+
- `KAFSIEM_PACKS_DIR`
140193
- `UI_MODE`
141194
- `PROFILE`
142195
- `UI_POLICY_PATH`
143196

144-
When AgentOps is enabled, the collector writes `agentops-state.json` into the runtime data volume and the web UI reads that state directly.
197+
When AgentOps is enabled, the collector writes `agentops.db` into the runtime data volume and the analyst API serves typed `/api/v1/...` resources from that SQLite store.
145198

146199
Mount contract:
147200

148201
- `/config`: policy and UI steering files
149-
- `/data`: generated AgentOps state and replay metadata
202+
- `/data`: generated AgentOps SQLite state (`agentops.db` plus WAL/SHM sidecars), alerts JSON, and replay metadata
203+
- `/packs`: active bundled or mounted pack directories
150204

151205
Content behavior is explicit:
152206

@@ -157,6 +211,9 @@ Content behavior is explicit:
157211
- replay always uses a dedicated consumer group and never mutates the live tracking group
158212

159213
Operator reference and examples live in [docs/agentops-operator-guide.md](https://github.com/scalytics/kafSIEM/blob/main/docs/agentops-operator-guide.md).
214+
The analyst API contract lives in [api/openapi.yaml](https://github.com/scalytics/kafSIEM/blob/main/api/openapi.yaml);
215+
client guidance is in [docs/api-clients.md](https://github.com/scalytics/kafSIEM/blob/main/docs/api-clients.md)
216+
and problem details are registered in [docs/agentops-api-errors.md](https://github.com/scalytics/kafSIEM/blob/main/docs/agentops-api-errors.md).
160217

161218
## Operations
162219

api/cmd/specgen/main.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
"path/filepath"
7+
8+
"github.com/scalytics/kafSIEM/api/specgen"
9+
)
10+
11+
func main() {
12+
root, err := os.Getwd()
13+
if err != nil {
14+
log.Fatal(err)
15+
}
16+
root = filepath.Clean(filepath.Join(root, ".."))
17+
for _, output := range specgen.Outputs() {
18+
target := filepath.Join(root, output.Path)
19+
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
20+
log.Fatal(err)
21+
}
22+
if err := os.WriteFile(target, []byte(output.Content), 0o644); err != nil {
23+
log.Fatal(err)
24+
}
25+
}
26+
}

api/doc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Package api holds the generated OpenAPI contract for the standalone
2+
// kafSIEM analyst API.
3+
package api

api/generate.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package api
2+
3+
//go:generate go run ./cmd/specgen

api/generate_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package api
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/scalytics/kafSIEM/api/specgen"
9+
)
10+
11+
func TestGeneratedArtifactsAreUpToDate(t *testing.T) {
12+
root := filepath.Clean(filepath.Join(".."))
13+
for _, output := range specgen.Outputs() {
14+
path := filepath.Join(root, output.Path)
15+
body, err := os.ReadFile(path)
16+
if err != nil {
17+
t.Fatalf("read %s: %v", output.Path, err)
18+
}
19+
if string(body) != output.Content {
20+
t.Fatalf("%s is stale; run `go generate ./api/...`", output.Path)
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)