release / release (push) Successful in 57s
Steward's first release: a DHCPv4 server with subnets per interface, reservations (by MAC address, client ID or either, with their own lease time), a web UI, REST API and CLI, Kea import, the web UI's certificate through Jarl, clients' last-seen times, the activity log by subnet, hidden interfaces and the address order per subnet and pool. make test and make e2e (124 checks with udhcpc and dhcpcd) pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
145 lines
7.3 KiB
Markdown
145 lines
7.3 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to Steward are documented here. The format follows
|
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
[Semantic Versioning](https://semver.org/).
|
|
|
|
## [0.1.0] - 2026-10-18
|
|
|
|
The first version of Steward, a DHCPv4 server with a web UI, a REST API
|
|
and a CLI, built the way Jarl is.
|
|
|
|
### Added
|
|
|
|
- **DHCPv4 server** (`stewardd serve`):
|
|
- Answers DISCOVER, REQUEST (selecting, init-reboot, renewing,
|
|
rebinding), DECLINE, RELEASE and INFORM, as RFC 2131 describes.
|
|
- Serves each subnet on its own network interface, with a socket per
|
|
interface bound to it, so a VLAN's clients only get that VLAN's
|
|
addresses.
|
|
- Several subnets on one interface are served together, as a shared
|
|
network.
|
|
- Opens an interface's socket when the interface appears, such as a
|
|
VLAN that comes up later, and closes it when its last subnet goes.
|
|
- **Address choice**, in this order:
|
|
1. the client's reservation;
|
|
2. the address it had before;
|
|
3. the address it asks for;
|
|
4. a pool address never handed out, else the one free the longest.
|
|
- **Reserved addresses** are never handed out to anyone else, even inside
|
|
a pool.
|
|
- **Leases** are kept in SQLite and saved before the ACK is sent. Ended
|
|
ones stay 30 days, so returning clients get their address again.
|
|
- **Conflict checks:**
|
|
- An address is pinged before it is offered, and one that answers is
|
|
held back.
|
|
- An address a client declines is held back for a day.
|
|
- Both use the `decline_hold` setting.
|
|
- **Authority:** a request for an address that doesn't belong on the
|
|
interface gets a NAK, so the client starts over at once. This can be
|
|
turned off when another server shares a network.
|
|
- **Options:**
|
|
- 27 by name (`routers`, `domain-name-servers`, `domain-search`,
|
|
`ntp-servers`, `classless-static-route`, …), and any other by number
|
|
with a type.
|
|
- Set globally, per subnet and per reservation, the most specific
|
|
winning.
|
|
- When a client sends a parameter request list, it gets what it asked
|
|
for, in that order.
|
|
- **Configuration changes:**
|
|
- Validated as a whole, with stable problem codes (docs/validation.md).
|
|
- Saved with a history entry, and can be undone after a check that
|
|
nothing changed since.
|
|
- `?dry_run=1` (or `steward -n`) previews a change.
|
|
- **REST API** (docs/api.md):
|
|
- users, sessions with CSRF protection, and API tokens limited by role
|
|
or grant (`config`, `leases`, `audit`);
|
|
- an audit log;
|
|
- a local unix socket where root needs no token.
|
|
- **CLI** `steward` (docs/cli.md):
|
|
- commands: status, subnet, reservation, lease, activity, settings,
|
|
option, interface, history (with undo), import kea, user, token,
|
|
password, audit, config;
|
|
- output as tables, JSON, YAML or IDs.
|
|
- **Web UI:**
|
|
- a dashboard of interfaces, pool use, problems and recent messages;
|
|
- subnets with their leases, reservations and settings;
|
|
- leases, with reserve and delete;
|
|
- reservations;
|
|
- live DHCP activity;
|
|
- settings and global options;
|
|
- history with undo, the audit log, users and tokens.
|
|
- A new subnet suggests its network and a pool from the interface's
|
|
address.
|
|
- **Kea import:** `steward import kea` (`POST /import/kea`) reads a
|
|
`kea-dhcp4.conf` and its lease files (docs/kea.md):
|
|
- global, shared-network and subnet options, pools, lease times and
|
|
reservations;
|
|
- each subnet's interface: Kea's, else the host's interface with an
|
|
address in the subnet, else `--interface PREFIX=IFACE`.
|
|
- It lists what it doesn't support instead of dropping it silently.
|
|
- Importing again keeps subnets' and reservations' IDs and Steward's
|
|
subnet names.
|
|
- **`stewardd`** commands: `init` (asks for the administrator's name),
|
|
`user add|password|token`, `check`, `backup` (with pruning), `restore`,
|
|
`config --example`.
|
|
- **The web UI's certificate from Let's Encrypt, through Jarl**
|
|
(docs/certificates.md, docs/jarl.md):
|
|
- `tls.acme` in `steward.yaml` names the certificate, and `jarl:` the
|
|
Jarl server and a token that may only write the challenge record.
|
|
- Steward gets the certificate with the DNS-01 challenge, writing the
|
|
record through Jarl's API into every view that has the zone.
|
|
- It renews with a third of the lifetime left, and swaps the new
|
|
certificate in without a restart.
|
|
- A check runs before every order, and on demand: Jarl, the zone, the
|
|
token's permission, a test record, the zone's public name servers and
|
|
public resolvers, clean-up. Each step says what to fix.
|
|
- It starts with Let's Encrypt's staging service by default.
|
|
- `steward cert`, `cert check`, `cert renew`; Server → Certificate in the
|
|
web UI; `GET /certificate`, `POST /certificate/check|renew`.
|
|
- Dashboard problems: `certificate_failed`, `certificate_expiring`,
|
|
`certificate_staging`.
|
|
- **HTTPS and plain HTTP on one port:** with a certificate, plain HTTP is
|
|
redirected to HTTPS, except from the server itself (also for
|
|
`tls.cert_file`).
|
|
- **Disabled reservations** (`steward reservation disable|enable`, Disable
|
|
in the web UI): kept but ignored, so the client gets a pool address like
|
|
any other. Subnets get Disable/Enable buttons in the web UI too.
|
|
- **Hidden interfaces:** `interfaces.exclude` in `steward.yaml` (names or
|
|
shell patterns such as `docker*`) leaves interfaces out of the web UI's
|
|
interface picker, `steward interface list` and `GET /interfaces`.
|
|
- **Last seen:** with the ping check on, active leases' addresses are
|
|
pinged every minute, and a client that answers gets a last-seen time
|
|
(Leases page, reservations' online badge, `steward lease list|show`,
|
|
`steward reservation list|show`, `last_seen` in the API). A client that
|
|
blocks pings stays online for as long as its lease lasts, without one.
|
|
- **The Reservations page refreshes itself** every 15 seconds, so online
|
|
and last seen stay current.
|
|
- **Activity by subnet:** `steward activity --subnet`, a subnet filter on
|
|
the Activity page, `GET /events?subnet=` (ID, name or prefix).
|
|
- **Address order** (docs/subnets.md): which never-used pool address a
|
|
new client gets, `sequential` (the lowest, as before), `reverse` or
|
|
`random`, in the settings, a subnet (`--address-order`) or a single
|
|
pool (`--pool 10.0.10.200-10.0.10.250:random`). A subnet's pools are
|
|
used in the order listed, or one at random (`--pool-order random`),
|
|
weighted by its never-used addresses. Pools now keep the order they are
|
|
given in. Kea's `allocator: random` is imported.
|
|
- **A reservation's own lease time** (`--lease-time 7d`, the reservation
|
|
dialog), over the subnet's.
|
|
- **Reservations by MAC address and client ID together**: either one gets
|
|
the client its address (a dual-boot machine sends two client IDs from
|
|
one MAC). The Leases page shows the client ID a client sent, and
|
|
reserving a lease uses both (`steward lease reserve --by` for one).
|
|
- **Token rotation** (`steward token rotate`, `POST /tokens/{id}/rotate`,
|
|
Rotate in the web UI): a new secret for a token, with an optional grace
|
|
period for the old one, as in Jarl.
|
|
- **Packaging:**
|
|
- a sandboxed systemd unit (`steward.service`, also `stewardd.service`)
|
|
whose only privilege is `CAP_NET_BIND_SERVICE`;
|
|
- a daily backup timer, and sysusers and tmpfiles files;
|
|
- Debian packages `steward` and `steward-cli`, and a Gitea release
|
|
workflow.
|
|
- **The Steward logo:** a key whose bow is a crown with Jarl's network
|
|
nodes, in Jarl's blue and white, with a STEWARD wordmark in Jarl's
|
|
letters.
|