HomeDocs › Third-Party Components

Third-Party Components

SpatiumDDI is an assembly job as much as it is a codebase. It does not reimplement DNS or DHCP — it runs BIND9, PowerDNS, Technitium and Kea, and it runs them on a Kubernetes distribution it did not write, on an operating system it did not write. This page is the catalogue of everything in that stack: what it is, which artifact it ships in, what license it carries, and why it is there.

Two files cover this ground, and they are not the same thing.

File Purpose Authoritative for
NOTICE Legal attribution notice, shipped in the repo root and in every image License obligations
This page Operator-facing catalogue — versions, artifact placement, rationale Understanding what runs where

If the two ever disagree about a license, NOTICE wins and the discrepancy is a bug worth filing.

Neither file enumerates every transitive dependency. They cover components that are bundled, shipped, or directly depended on — the things an operator can point at in a running system, and the things a license auditor asks about. The full transitive set for the Python and npm layers lives in backend/pyproject.toml + frontend/package-lock.json; for the OS layer, ask the package manager on a running appliance (see Verifying a running system).

Artifacts

The “Where” column throughout this page refers to these:

Artifact What it is
API image ghcr.io/spatiumddi/spatiumddi-api — FastAPI control plane, Celery worker, Celery beat, and the migrate job. One image, four roles
Frontend image ghcr.io/spatiumddi/spatiumddi-frontend — the built React SPA behind nginx
DNS agent images dns-bind9, dns-powerdns, dns-technitium, dns-dnsdist — each pairs a DNS engine with the Python sync agent
DHCP agent image dhcp-kea — Kea DHCPv4 + DHCPv6 + radvd + the Python sync agent
Looking Glass image looking-glass — GoBGP collector + agent
Supervisor image spatium-supervisor — host-side controller on the OS appliance
Appliance OS The bootable Debian image, including its baked k3s
Helm charts charts/spatiumddi (generic Kubernetes) and charts/spatiumddi-appliance (on-appliance k3s)

Versions below are the pins on main at the time of writing. They move; the Pinned in column names the file that is actually authoritative, and that is the one to check rather than trusting this table’s numbers.

DNS, DHCP and routing engines

The reason the project exists. Every one of these is a separate upstream daemon running as its own process — SpatiumDDI generates their configuration and talks to their control channels, it does not link against them.

Component Version License Where Pinned in
ISC BIND 9 >= 9.20.26 (Alpine) MPL 2.0 DNS agent image agent/dns/images/bind9/Dockerfile
PowerDNS Authoritative Server Alpine pdns GPL v2 DNS agent image agent/dns/images/powerdns/Dockerfile
Technitium DNS Server 15.4.0 (digest-pinned) GPL v3 DNS agent image agent/dns/images/technitium/Dockerfile
PowerDNS dnsdist Alpine dnsdist GPL v2 DNS agent image agent/dns/images/dnsdist/Dockerfile
ISC Kea DHCP Alpine kea, v4 + v6 MPL 2.0 DHCP agent image agent/dhcp/images/kea/Dockerfile
radvd Alpine radvd BSD-style DHCP agent image agent/dhcp/images/kea/Dockerfile
GoBGP 4.7.0 (built from source) Apache 2.0 Looking Glass image agent/looking-glass/images/gobgp/Dockerfile
BIND dig / nsupdate bind-tools MPL 2.0 DNS + supervisor + API images several Dockerfiles

Notes worth carrying:

Kubernetes and orchestration

Component Version License Where Pinned in
k3s v1.35.6+k3s1 Apache 2.0 Appliance OS appliance/scripts/fetch-k3s.sh
containerd + runc embedded in k3s Apache 2.0 Appliance OS (k3s bundle)
CoreDNS k3s airgap bundle Apache 2.0 Appliance OS (k3s bundle)
Flannel embedded in k3s, host-gw backend Apache 2.0 Appliance OS appliance/mkosi.extra/etc/rancher/k3s/config.yaml
local-path-provisioner k3s airgap bundle Apache 2.0 Appliance OS (k3s bundle)
etcd embedded in k3s Apache 2.0 Appliance OS (k3s bundle)
Helm k3s helm-controller Apache 2.0 Appliance OS (k3s bundle)
Traefik in k3s bundle, disabled MIT Appliance OS config.yaml disable: list
metrics-server in k3s bundle, disabled Apache 2.0 Appliance OS config.yaml disable: list
MetalLB chart + images 0.15.3 Apache 2.0 Helm chart (opt-in) charts/spatiumddi-metallb/Chart.yaml
FRRouting via MetalLB frr-k8s GPL v2 Helm chart (opt-in) charts/spatiumddi-metallb values
CloudNativePG chart 0.28.2 Apache 2.0 Helm chart (opt-in) charts/spatiumddi-appliance/Chart.yaml
Patroni k8s/ha/ overlay MIT Bare-metal HA overlay k8s/ha/
HAProxy 2.9-alpine GPL v2 (+ LGPL libs) Patroni HA overlay k8s/ha/

Three of these deserve a sentence, because their state is not what you would assume from their presence:

Data services

Component Version License Where Pinned in
PostgreSQL 16-alpine PostgreSQL License Compose + Helm chart docker-compose.yml
Redis 8.8-alpine RSALv2 / SSPLv1 / AGPLv3 (Redis 8+) Compose + Helm chart docker-compose.yml
Prometheus node-exporter v1.11.1, default off Apache 2.0 Appliance chart charts/spatiumddi-appliance/values.yaml
kube-state-metrics v2.18.0, default off Apache 2.0 Appliance chart charts/spatiumddi-appliance/values.yaml
prometheus-client see manifest Apache 2.0 AND BSD 2-Clause API image backend/pyproject.toml

On Redis’s license: Redis relicensed away from BSD at 7.4 (RSALv2 + SSPLv1) and added an AGPLv3 option at 8.0. SpatiumDDI ships the stock upstream redis:8.8-alpine image unmodified and talks to it as a network service over its own protocol — no Redis code is linked into or vendored by SpatiumDDI.

Operators who would rather not run that license family can point the deployment at any Redis-protocol-compatible server via the connection URL. The control plane uses only GET / SET / DEL / INCR / EXPIRE / SCAN and pub/sub — no modules, no Lua, no streams — and Celery’s Redis broker is the other consumer. This is an untested configuration rather than a supported one; if you run SpatiumDDI on a Redis alternative, tell us how it went.

The Helm chart used to bundle Bitnami’s PostgreSQL and Redis subcharts. Bitnami pruned its Docker Hub namespace in late 2025 in favour of paid images, so the pinned tags stopped resolving; the chart now ships plain StatefulSets using the official upstream images instead.

Control-plane backend (Python)

Runs in the API image. Authoritative list, with versions: backend/pyproject.toml.

Component License What it does here
Python 3.12 PSF Runtime
FastAPI / Starlette MIT / BSD 3-Clause HTTP framework
Uvicorn BSD 3-Clause ASGI server
SQLAlchemy / Alembic MIT ORM + migrations
asyncpg Apache 2.0 Async PostgreSQL driver
Pydantic / pydantic-settings MIT Schema validation, settings
Celery BSD 3-Clause Task queue
redis-py + hiredis MIT Redis client
structlog MIT OR Apache 2.0 Structured JSON logging
cryptography Apache 2.0 OR BSD 3-Clause Fernet secrets at rest, cert handling
pyOpenSSL Apache 2.0 TLS chain capture (stdlib ssl cannot on 3.12)
python-jose / joserfc MIT / BSD 3-Clause JWT issue + verify
bcrypt Apache 2.0 Local password hashing
pyotp MIT TOTP second factor
ldap3 LGPL v3 LDAP authentication
python3-saml MIT SAML SP flow
pyrad BSD 3-Clause RADIUS authentication
tacacs_plus BSD TACACS+ authentication
httpx BSD 3-Clause HTTP client (all outbound integrations)
dnspython ISC DDNS, AXFR, resolution
Jinja2 BSD 3-Clause Config rendering
pywinrm MIT Windows DNS/DHCP over WinRM
pysnmp BSD 2-Clause SNMP polling
paramiko LGPL 2.1 SSH transport
smbprotocol MIT SMB backup targets
openpyxl MIT XLSX import/export
reportlab BSD PDF reports (audit, compliance, IPAM)
croniter MIT Schedule parsing
icalendar / caldav / python-dateutil BSD 2-Clause / Apache 2.0 (dual with GPL v3) / dual Wake-on-LAN calendar gate
idna BSD 3-Clause IDNA2008 name normalization
boto3 Apache 2.0 AWS mirror + Route 53 DNS + S3 backups
azure-identity / azure-mgmt-* MIT Azure mirror + Azure DNS + Blob backups
google-cloud-* / google-auth Apache 2.0 GCP mirror + Cloud DNS + GCS backups
docker Apache 2.0 Cert-reload signal on non-k3s appliances
PyYAML MIT HelmChartConfig rewriting
openai / anthropic Apache 2.0 / MIT Operator Copilot model clients

Cloudflare has no SDK entry on purpose. The Cloudflare DNS driver speaks plain REST over httpx rather than pulling in the official SDK, which ships a pydantic-v1 compatibility shim.

On the two copyleft Python libraries: ldap3 (LGPL v3) and paramiko (LGPL 2.1) are imported as libraries into an Apache-2.0 application. LGPL permits this; what it requires is that a recipient can replace the library. They are installed as ordinary, separately-replaceable site-packages in the image — nothing is statically linked or vendored.

Agent runtimes (Python)

The DNS, DHCP, Looking Glass and supervisor agents each carry a much smaller dependency set than the control plane. Common to all: httpx, structlog, pydantic.

Agent Additional License Why
DNS dnspython, cryptography ISC, Apache 2.0 OR BSD 3-Clause DDNS + TSIG
DHCP Scapy GPL v2 Passive DHCP fingerprinting — opt-in at runtime, installed unconditionally so the toggle needs no second image
Supervisor cryptography, PyYAML Apache 2.0 OR BSD 3-Clause, MIT Ed25519 identity, chart values
Looking Glass Talks to GoBGP over its API

Frontend

Runs in the frontend image. Authoritative list: frontend/package.json.

Component License What it does here
React + react-dom 18 MIT UI framework
TypeScript Apache 2.0 Language
Vite MIT Build tool + dev server
Tailwind CSS + tailwindcss-animate MIT Styling
shadcn/ui MIT Component patterns (vendored source, not a dependency)
Radix UI context-menu MIT Accessible primitive
TanStack Query MIT Server-state cache
React Router MIT Routing
axios MIT HTTP client
Recharts MIT Charts
lucide-react ISC Icons
react-markdown + remark-gfm MIT Copilot message rendering
dnd-kit MIT Drag-and-drop
clsx, tailwind-merge MIT Class composition
nginx 1.31-alpine BSD 2-Clause Static serving + API reverse proxy

Appliance operating system

The bootable image is Debian 13 (trixie), built with mkosi. The full package list is appliance/mkosi.conf — this is the operator-meaningful subset.

Component License Why it is on the image
Linux kernel GPL v2 linux-image-amd64, not the cloud variant — the cloud kernel strips KMS, leaving an 80x25 console instead of the dense one the dashboard needs
Debian base DFSG (mixed) Base distribution
systemd + udev + systemd-resolved LGPL 2.1+ Init, device management, host resolver
GRUB 2 GPL v3 Hybrid BIOS + UEFI boot
NetworkManager GPL v2+ Interface configuration
nftables GPL v2 Default-deny inbound firewall, per-role drop-ins
chrony GPL v2 NTP
Net-SNMP BSD-style snmpd — needs unfiltered /proc and /sys, which is why it runs on the host and not in a container
lldpd ISC Neighbour discovery
rsyslog + rsyslog-gnutls GPL v3 / LGPL v3 Syslog forwarding, TLS transport
OpenSSH BSD-style Operator access
cloud-init GPL v3 / Apache 2.0 First-boot provisioning
unattended-upgrades GPL v2 Security patches (no kernel upgrades)
newt / whiptail LGPL v2 Install wizard dialogs
gdisk, dosfstools, e2fsprogs, parted GPL v2 / GPL v3 Disk partitioning + filesystems
rsync GPL v3 Rootfs mirror to target disk
qemu-guest-agent / open-vm-tools GPL v2 / GPL v2 + BSD Hypervisor integration; both no-op off their platform
zstd BSD 3-Clause / GPL v2 Image + airgap tarball compression
jq, curl, less, htop, tcpdump, dnsutils MIT / curl / GPL / BSD / MPL 2.0 Operator diagnostics
Rich + psutil (python3-rich, python3-psutil) MIT / BSD 3-Clause The console dashboard on tty1

There is no Docker on the appliance. It was removed in #183 Phase 7 — the image is k3s-only, and k3s’s static binary carries its own containerd plus kubectl / ctr / crictl as argv symlinks.

Operator tooling inside the API image

The Tools page (/tools) and PCAP capture shell out to real binaries, so they ship in the API image rather than being reimplemented. All are invoked through a sandboxed argv builder, never a shell string.

Component License Used by
nmap NPSL (Nmap Public Source License) Port/service scan tools
tcpdump + libpcap BSD 3-Clause PCAP capture (#59), granted cap_net_raw
mtr (mtr-tiny) GPL v2 Path analysis
iputils-ping, traceroute BSD / GPL v2 Reachability
whois GPL v2 Registration lookup
BIND dig (dnsutils) MPL 2.0 DNS query + propagation check
PostgreSQL client 16 PostgreSQL License pg_dump / pg_restore for backup + restore
xmlsec1 (libxmlsec1-openssl) MIT SAML assertion signature verification

nmap’s license is not OSI-approved. The NPSL is a GPL v2 derivative with added restrictions on redistribution inside commercial products. SpatiumDDI is Apache 2.0 and ships nmap as an unmodified, separately-installed Debian package invoked as a subprocess — no linking, no derivative work. Anyone repackaging SpatiumDDI commercially should read the NPSL themselves rather than assume the Apache license covers it.

Container bases and init

Component Version License Where
Alpine Linux 3.23 MIT (+ GPL v2 kernel) All agent images, supervisor
Debian slim trixie / bookworm DFSG (mixed) Appliance builder, Technitium agent build stage
python:3.12-slim 3.12 PSF + Debian API image
node 22-alpine MIT Frontend build stage
nginx 1.31.3-alpine BSD 2-Clause Frontend runtime
ASP.NET Core runtime 10.0 MIT Technitium agent image
tini Alpine/Debian pkg MIT PID 1 in every agent image
su-exec / gosu Alpine / Debian pkg MIT / Apache 2.0 Privilege drop at entrypoint

Alpine is pinned at 3.23, not 3.24, and that pin is load-bearing: 3.24 ships Python 3.13 while the agent Dockerfiles install into 3.12 paths, which produces a ModuleNotFoundError crashloop rather than a build failure. Dependabot is configured to hold the pin.

Build and test toolchain

Not shipped to operators — listed because a contributor will meet all of it, and because CI gates depend on specific behaviour from several.

Component License Role
mkosi LGPL 2.1 Builds the appliance disk image
Go BSD 3-Clause Builds GoBGP from source in the Looking Glass image
Trivy Apache 2.0 Image CVE gate (HIGH/CRITICAL, --ignore-unfixed)
pytest + pytest-asyncio / cov / xdist / split MIT Backend test suite
ruff / black / mypy MIT Backend lint + typecheck
ESLint / Prettier / typescript-eslint MIT Frontend lint
Playwright Apache 2.0 README/docs screenshot generation
Jekyll + kramdown MIT This documentation site
Helm Apache 2.0 Chart packaging

License obligations

SpatiumDDI itself is Apache 2.0. Everything above keeps its own license. The combination is distributed as separate, independently-installed programs — container images built from upstream distribution packages, and a disk image built by a distribution’s own package manager. Nothing copyleft is statically linked into, or vendored inside, the Apache-2.0 codebase.

The practical consequences:

If you are performing a license review and need something this page does not answer, open an issue — that is a documentation bug, not a support question.

Verifying a running system

This page can drift. A running system cannot.

Python packages in the API image, with versions and licenses:

docker compose exec api python3 -m pip list
docker compose exec api python3 -m pip show ldap3 paramiko

OS packages on the appliance:

dpkg-query -W -f='${Package}\t${Version}\t${Homepage}\n' | sort

Packages inside an Alpine-based agent image:

docker compose exec dns-bind9 apk list --installed

What k3s actually bundles in the release you are running — the manifest is baked onto the appliance at build time, alongside k3s’s own LICENSE:

cat /usr/share/doc/k3s/k3s-images.txt
cat /usr/share/doc/k3s/LICENSE

Images running on the appliance’s k3s cluster right now:

kubectl get pods -A -o jsonpath='{range .items[*].spec.containers[*]}{.image}{"\n"}{end}' | sort -u

See also