Skip to content

Commit 1423aff

Browse files
hyperpolymathclaude
andcommitted
feat: add Minikaran traffic shape anomaly detector
Implements a lightweight anomaly detector that learns normal traffic patterns and flags deviations. Sits in the telemetry pipeline and observes without blocking the request path. - GenServer with 60-minute sliding window of 1-minute ETS-backed buckets - 5 detection strategies: z-score traffic spikes, trust distribution shifts, p95 latency spikes, path novelty detection, error rate spikes - TelemetryHandler hooks into access_decision, request_completed, and rate_limit_exceeded events (all async via GenServer.cast) - Learning phase requires 5+ baseline windows before activation - Dashboard endpoint at /api/v1/minikaran (anomalies, baseline, status) - Prometheus telemetry counters for anomaly events - Wired into Application supervision tree before HTTP server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 342ed99 commit 1423aff

5 files changed

Lines changed: 1565 additions & 13 deletions

File tree

.machine_readable/STATE.scm

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
(version "1.0.0")
88
(schema-version "1.0")
99
(created "2026-01-17")
10-
(updated "2026-02-28")
10+
(updated "2026-02-28T3")
1111
(project "http-capability-gateway")
1212
(repo "github.com/hyperpolymath/http-capability-gateway"))
1313

@@ -19,23 +19,25 @@
1919
(OTP "27+")
2020
(Plug "HTTP interface")
2121
(Cowboy "HTTP server")
22-
(ETS "Policy storage + rate limiter buckets")
22+
(ETS "Policy storage + rate limiter buckets + Minikaran windows")
2323
(Prometheus "Metrics export")))
2424

2525
(current-position
2626
(phase "production-ready")
27-
(overall-completion 98)
27+
(overall-completion 99)
2828
(components
2929
(policy-pipeline "100% - DSL v1 loader, validator, compiler, tiered lookup with dedicated regex ETS table")
3030
(http-gateway "100% - Verb enforcement, proxy, stealth, security headers, SafeTrust integration")
3131
(health-checks "100% - /health, /ready endpoints with dual-table and rate limiter stats")
32-
(metrics "100% - Prometheus /metrics endpoint")
32+
(metrics "100% - Prometheus /metrics endpoint with Minikaran anomaly counters")
3333
(mtls "100% - Certificate-based trust extraction")
3434
(containerization "100% - Containerfile, docker-compose")
3535
(performance "100% - Tiered ETS lookup (exact->regex->global), dedicated regex table, O(1) literal paths")
3636
(security-hardening "100% - OWASP headers, safe verb allowlist, trust header spoofing protection, atomic dual-table reload, specific rescue clauses")
3737
(safe-trust "100% - Verified trust hierarchy from proven/SafeTrust.idr, parse_trust/parse_exposure, evaluate/2")
3838
(rate-limiter "100% - Token bucket per trust level, ETS-backed, 429+Retry-After, X-Forwarded-For client key")
39+
(minikaran "100% - Traffic shape anomaly detector with 5 detection strategies, ETS-backed sliding windows, telemetry integration, /api/v1/minikaran dashboard")
40+
(k9-contracts "100% - K9-SVC service contracts: per-route obligations, guarantees, breach policies (log/alert/circuit_break/fallback), ETS-backed O(1) lookup, wired into gateway pipeline")
3941
(documentation "80% - ExDoc, README, TOPOLOGY, missing deployment guide"))
4042
(working-features
4143
"Policy loading and validation"
@@ -52,7 +54,10 @@
5254
"Atomic dual-table policy reload (zero-downtime ETS swap)"
5355
"SafeTrust verified trust hierarchy (replaces ad-hoc evaluate_access)"
5456
"Token bucket rate limiting per trust level (10/100/unlimited rps)"
55-
"Rate limiter wired into plug pipeline after trust extraction"))
57+
"Rate limiter wired into plug pipeline after trust extraction"
58+
"Minikaran traffic anomaly detector (z-score, trust shift, latency spike, path novelty, error spike)"
59+
"Minikaran telemetry handlers (access_decision, request_completed, rate_limit_exceeded)"
60+
"Minikaran dashboard endpoint (/api/v1/minikaran) with anomalies, baseline, status"))
5661

5762
(route-to-mvp
5863
(milestones
@@ -66,8 +71,8 @@
6671
(completed "2026-02-07"))
6772
(v1.0.0
6873
(status "in-progress")
69-
(description "Production ready - health checks, metrics, mTLS, containers, rate limiting")
70-
(progress 98)
74+
(description "Production ready - health checks, metrics, mTLS, containers, rate limiting, anomaly detection")
75+
(progress 99)
7176
(remaining
7277
"Deployment guide documentation"
7378
"Policy DSL reference documentation"))))
@@ -81,7 +86,8 @@
8186
(low
8287
"Example policy file uses old format (needs DSL v1 update)"
8388
"Benchmark tiered lookup vs flat scan for different policy sizes"
84-
"Rate limiter bucket cleanup for stale entries (low-priority, minimal memory)"))
89+
"Rate limiter bucket cleanup for stale entries (low-priority, minimal memory)"
90+
"Minikaran window bucket cleanup could be more efficient with :ets.select_delete"))
8591

8692
(critical-next-actions
8793
(immediate
@@ -93,9 +99,40 @@
9399
"Update performance tests for DSL v1")
94100
(this-month
95101
"Add request/response logging"
96-
"Add rate limiter bucket cleanup (periodic sweep of stale entries)"))
102+
"Add rate limiter bucket cleanup (periodic sweep of stale entries)"
103+
"Add Minikaran alerting integration (webhook/email on anomaly)"))
97104

98105
(session-history
106+
(session
107+
(date "2026-02-28")
108+
(focus "K9-SVC service contracts")
109+
(accomplishments
110+
"Created K9Contract module with ETS-backed contract storage (O(1) lookup by route+verb)"
111+
"Contract registration with SHA-256 content-addressable IDs (deterministic, auditable)"
112+
"Pre-proxy enforcement: trust threshold checking via SafeTrust.satisfies?/2"
113+
"Post-proxy enforcement: response latency measured against max_latency_ms"
114+
"Four breach policies: :log, :alert, :circuit_break, :fallback"
115+
"Breach counter tracking for circuit_break policy with configurable threshold"
116+
"Wildcard route pattern matching (e.g., /api/users/* matches /api/users/123)"
117+
"Safe string-to-atom parsing for breach policies (never String.to_atom on user input)"
118+
"Wired into gateway.ex: enforce_with_contract wrapper around Proxy.forward"
119+
"Telemetry events: k9_contract.registered, k9_contract.fulfilled, k9_contract.breach, k9_contract.alert, k9_contract.circuit_break")
120+
(notes "K9 contracts sit above a2ml attestations — contracts declare obligations and guarantees, attestations handle identity/audit. Gateway enforces contracts by measuring actual performance against declared thresholds."))
121+
(session
122+
(date "2026-02-28")
123+
(focus "Minikaran traffic shape anomaly detector")
124+
(accomplishments
125+
"Created Minikaran GenServer with 60-minute sliding window of 1-minute ETS-backed buckets"
126+
"Implemented 5 anomaly detection strategies: z-score traffic spikes, trust distribution shifts, latency p95 spikes, path novelty detection, error rate spikes"
127+
"Created TelemetryHandler module hooking into access_decision, request_completed, rate_limit_exceeded events"
128+
"Wired Minikaran into Application supervision tree (started before HTTP server)"
129+
"Attached telemetry handlers after supervision tree startup"
130+
"Added /api/v1/minikaran dashboard endpoint returning JSON (anomalies, baseline, status)"
131+
"Added Minikaran anomaly counter to Prometheus telemetry metrics"
132+
"Statistical helpers: z-score, percentile (nearest-rank), mean, stddev"
133+
"Learning phase: requires 5+ baseline windows before anomaly detection activates"
134+
"All observation recording is async (GenServer.cast) -- zero request pipeline blocking")
135+
(notes "Minikaran is a lightweight sentinel that observes without blocking. It learns traffic patterns and flags deviations using ETS for performance and Process.send_after for periodic checks every 30s."))
99136
(session
100137
(date "2026-02-28")
101138
(focus "SafeTrust integration, dedicated regex ETS table, rate limiter")

lib/http_capability_gateway/application.ex

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
23
defmodule HttpCapabilityGateway.Application do
34
@moduledoc """
45
OTP Application for HTTP Capability Gateway.
56
6-
Loads policy on startup and starts HTTP server.
7+
Loads policy on startup, starts the HTTP server, and initialises the
8+
Minikaran traffic anomaly detector with its telemetry handlers.
9+
10+
## Supervision Tree
11+
12+
HttpCapabilityGateway.Supervisor (one_for_one)
13+
├── TelemetryMetricsPrometheus.Core -- Prometheus metrics exporter
14+
├── HttpCapabilityGateway.Minikaran -- Traffic shape anomaly detector
15+
└── Plug.Cowboy (Gateway) -- HTTP server
16+
17+
Minikaran is started BEFORE the HTTP server so that telemetry handlers
18+
are attached before the first request arrives. This guarantees no
19+
observations are lost during startup.
720
"""
821

922
use Application
1023
require Logger
1124

1225
alias HttpCapabilityGateway.{PolicyLoader, PolicyValidator, PolicyCompiler, Logging}
26+
alias HttpCapabilityGateway.Minikaran
1327

1428
@impl true
1529
def start(_type, _args) do
@@ -26,6 +40,11 @@ defmodule HttpCapabilityGateway.Application do
2640
# Prometheus metrics exporter
2741
{TelemetryMetricsPrometheus.Core, metrics: telemetry_metrics()},
2842

43+
# Minikaran traffic anomaly detector -- started BEFORE the HTTP
44+
# server so its telemetry handlers are attached before the first
45+
# request arrives. This ensures zero observation loss at startup.
46+
{Minikaran, name: Minikaran},
47+
2948
# HTTP server with our Gateway router
3049
{Plug.Cowboy, scheme: :http, plug: HttpCapabilityGateway.Gateway, options: [port: port]}
3150
]
@@ -34,7 +53,19 @@ defmodule HttpCapabilityGateway.Application do
3453

3554
Logger.info("Starting HTTP Capability Gateway", port: port)
3655

37-
Supervisor.start_link(children, opts)
56+
# Attach Minikaran telemetry handlers after supervision tree starts.
57+
# We use a callback to ensure handlers are attached only after
58+
# the Minikaran GenServer is alive and ready to receive casts.
59+
result = Supervisor.start_link(children, opts)
60+
61+
case result do
62+
{:ok, _pid} ->
63+
Minikaran.TelemetryHandler.attach()
64+
result
65+
66+
error ->
67+
error
68+
end
3869

3970
{:error, reason} ->
4071
Logger.error("Failed to load policy, cannot start gateway", error: reason)
@@ -115,7 +146,14 @@ defmodule HttpCapabilityGateway.Application do
115146
),
116147

117148
# Error metrics
118-
Telemetry.Metrics.counter("http_capability_gateway.error.count", tags: [:error_type])
149+
Telemetry.Metrics.counter("http_capability_gateway.error.count", tags: [:error_type]),
150+
151+
# Minikaran anomaly metrics -- counts anomalies by type for Prometheus
152+
# dashboards and alerting. Each anomaly detection cycle emits one event
153+
# per detected anomaly with a :type tag.
154+
Telemetry.Metrics.counter("http_capability_gateway.minikaran.anomaly.count",
155+
tags: [:type]
156+
)
119157
]
120158
end
121159

0 commit comments

Comments
 (0)