Skip to content

Agent Code Structure

Repository digilan/edge/gateway, module gitlab.com/digilan/edge/gateway. Go, cross-compiled for OpenBSD 7.8 (GOOS=openbsd, amd64 for gateways, arm64 for the Apple-silicon development VM).

edge/gateway/
├── cmd/
│   ├── agent/            # the edge-agent binary (cobra)
│   ├── gencheck/         # writes every generated file for a sample config, to check on OpenBSD
│   └── otasign/          # sign / verify ed25519 release signatures (used by CI)
├── internal/             # packages, below
├── packaging/openbsd/    # rc.d script, setup-device.sh, shell dotfiles
├── dev/                  # local OpenBSD VM and the bench check
├── docs/                 # manual-agent-recovery.md
├── examples/             # sample device configs
└── Makefile

cmd/agent

File Command / role
root.go, main.go Root command, global --log-level / --log-format
serve.go serve: the daemon. Wires every package below, arms the rollback guard (60 s), starts the supervisors
setup.go setup: first enrollment
reenroll.go reenroll: enroll against another environment
status.go, style.go status: bubbletea TUI over state.json
modem.go modem status, modem at
apply.go apply -f: apply a config file without Nexus
show.go show pf -f, show interfaces
version.go, completion.go version, completion
otakey.go Not a command: holds otaSigningPublicKey, set by -X main.otaSigningPublicKey=... at build time. Empty means self-update is disabled

internal/

Package Purpose
config Device config types, the agent's env Config, default system rules, validation
configstore Persists the applied and previous config (config.json, config.prev.json)
identity identity.json: gateway id, API token, addresses
connector ConnectRPC client to Nexus and WebSocket to the Realtime Durable Object; command dispatch, state reports, reenroll
agentstate Writes state.json for the TUI
state Collects system state: interfaces, pf counters, ARP, leases, uplinks, WireGuard
pf pf.conf generation and application; schedule anchors
ifctl Interface configuration (hostname.if, ifconfig), WireGuard
rollback Confirm-or-rollback guard for config applies, including resume after reboot
wanfailover Generates the ifstated machine and helper that move the default route between uplinks
dhcpleased dhcpleased.conf, so only the intended uplink installs a default route
dhcp dhcpd.conf for per-interface DHCP servers
forwarding IPv4/IPv6 forwarding sysctls
dnsfilter unbound.conf: resolver, DNS filtering views, published names
fqdn Keeps pf tables filled with the addresses behind hostnames
ipsec Site-to-site IPsec (iked.conf)
ospf ospfd.conf
wwan Cellular modem detection, dialling and recovery
relaylink Connection to the assigned relay over WireGuard, with transport fallback
webproxy TLS proxy publishing a LAN service under its own name
accesscode Access codes the gateway mints for a published service
detection Suricata and forwarding of intrusion alerts and firewall blocks
logforward Log upload to Nexus (UploadLogs)
syslogfwd Forwarding logs to a customer-run collector
shell PTY sessions for the remote console
selfupdate OTA: download, verify (sha256 + ed25519), swap, watchdog
selfheal Standing recovery: known-good snapshot and isolation ladder

dev/

  • openbsd-vm.sh — local QEMU OpenBSD VM (fetch, init, install, run, status, ssh, stop). User-mode NAT; SSH on 127.0.0.1:2222; the host is 10.0.2.2 from inside. KVM/amd64 on Linux, HVF/arm64 on macOS.
  • bench-check.sh — runs cmd/gencheck, copies its output to the VM and runs the real OpenBSD parsers on it (pfctl -nf for pf.conf and each anchor, unbound-checkconf, ospfd -n, newsyslog -n, ksh -n and rcctl check for rc scripts, ifconfig for each hostname.if). See Validating the output.

Building

  • Release builds come from the tag pipeline only, with -trimpath, -X main.version=<tag> and the OTA signing public key baked in; see CI & Release Process.
  • make build-openbsd builds a local binary in bin/ with the version stamped but no signing key: it runs, but refuses every OTA update.