Servienta docs
§0

What it is

Servienta gives your test suite a controlled instance of the network services your application talks to — a file server on five transports and receivers for syslog, SNMP traps, RADIUS, TACACS+, DNS, NTP, Kafka, and IPFIX. Bring it up with one command, generate traffic, read back exactly what arrived, inject faults, and reset — reproducibly, offline.

The application under test is out of scope: Servienta never reaches into it. It only accepts, serves, and reports what it observed.

§1

Core concepts

Instance
One bring-up of Servienta. Mutations — reset, faults, response controls — are instance-wide.
Run
One test execution inside an instance, identified by a run id you choose. Messages are read back per run.
Source claim
A run declares the source addresses whose traffic belongs to it. Servienta attributes each message to a run by source — so two runs share one instance without reading each other's traffic.
Stand
One licensable service. The free image runs the file server (HTTP) and a demo receiver; a license unlocks the rest.
§2

Quickstart

Run Servienta, serve a file, record a message, read it back, reset. Free image, no license.

docker pull ghcr.io/servienta/servienta:latest
mkdir -p fixtures && echo hello > fixtures/hello.txt

docker run --rm -p 5000:5000 -p 5001:5001 -p 8080:8080 -p 9000:9000 \
  -v "$PWD/fixtures:/fixtures:ro" ghcr.io/servienta/servienta:latest

# discover endpoints, serve a fixture byte-for-byte
curl http://localhost:5001/api/v1/endpoints
curl http://localhost:8080/hello.txt

# declare a run, send traffic, read it back
curl -X PUT http://localhost:5001/api/v1/runs/run-1 -d '{"sources":["172.17.0.1"]}'
echo 'hello from my app' | nc localhost 9000
curl 'http://localhost:5001/api/v1/received/reference?run=run-1'

# reset to a known state
curl -X POST http://localhost:5001/api/v1/reset

Your app can't put a run id inside a raw syslog packet, so a run claims the source addresses its traffic comes from. Servienta attributes each message to a run by source; one source belongs to one active run.

The fixture tree is your host directory, mounted read-only — folders map to URL paths, edits are visible immediately, Servienta serves bytes as they are and never writes into it. Air-gapped host? Move the image as a file: docker save → docker load. Two instances on one machine? In-container ports are fixed, host ports are yours — remap the second one.

§3

Receivers

Send to a service, read it back parsed at /api/v1/received/<service>?run=<id>.

ServiceProtocolRecorded content
referenceTCP line (demo, free)line
syslogUDP · TCP · RELPfacility, severity, message
snmp-trapsv2c · v3 USMvariable bindings
radius / tacacsauthenticationusername (reply steerable)
dns / ntpresolution / timequery (reply steerable)
kafkabroker (in-process)topic, key, value
ipfixcollectorflow record fields
§4

Response control

Steer what RADIUS, TACACS+, DNS, and NTP answer, for the run. Default is a successful reply; reset restores it.

curl -X PUT .../api/v1/responses/radius -d '{"outcome":"reject","reason":"locked"}'
curl -X PUT .../api/v1/responses/dns    -d '{"outcome":"nxdomain"}'
curl -X PUT .../api/v1/responses/ntp    -d '{"outcome":"stratum","stratum":5}'
curl -X PUT .../api/v1/responses/dns    -d '{}'   # restore default
§5

Fault injection

Force failures on both sides to test your error paths. Reset lifts them.

# file faults: auth-reject | missing | truncate | corrupt
curl -X PUT .../api/v1/faults/files/hello.txt -d '{"kind":"truncate"}'

# receiver modes: refuse | drop | delay | cut | error
curl -X PUT .../api/v1/faults/receivers/syslog -d '{"mode":"drop"}'
§6

Licensing

A license enables a set of stands. It is an Ed25519-signed file, validated at startup, fully offline. The free image runs the file server and a demo receiver; the service receivers unlock with a license — Files, Standard, Enterprise, or a custom stand set.

# mount a license and start
curl -X PUT http://localhost:5001/api/v1/license -d @license.json

# or paste it in the console: License section -> Apply a license

Offline licensing of self-hosted software is compliance clarity, not DRM: it makes what is enabled signed and verifiable, and prevents forgery. Every shipped credential is throwaway and documented as such.

§7

API reference

Base path /api/v1 on the control port (default 8080). Full schema ships as openapi.yaml.

VerbPathPurpose
GET/versionContract version
GET/endpointsService addresses
GET/licenseLicense status
PUT/runs/{id}Declare a run (claim sources)
DEL/runs/{id}Release a run
GET/received/{service}Read messages
POST/resetReset the instance
PUT/responses/{service}Steer a reply
PUT/faults/files/{fixture}File fault
PUT/faults/receivers/{service}Receiver fault