Steward 0.1.0 (in development): a DHCPv4 server with a web UI, API and CLI

Subnets served per interface, pools, reservations, options at three
levels, leases in SQLite saved before the ACK, ping and decline conflict
checks, validated changes with history and undo, users and tokens, an
audit log, a Kea importer, a sandboxed systemd unit and Debian packages.
Tested with real udhcpc and dhcpcd clients in Docker (scripts/e2e.sh).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-14 12:14:07 +01:00
commit 3c0808591f
111 files changed
+17851

No files matched your search

+150
View File
@@ -0,0 +1,150 @@
// Package version holds Steward's version, set at build time with
//
// go build -ldflags "-X steward/internal/version.Version=1.2.3 -X steward/internal/version.Tag=v1.2.3"
//
// The Makefile sets Version from the VERSION file, and Tag only when the
// build is of that release: HEAD is the tag v<VERSION> and no tracked file
// is changed. Only such a build reports a version number. Other builds
// are development builds, identified by their commit (which Go records
// from git by itself) and by where they stand relative to the last tag
// (Describe, from git describe).
package version
import (
"regexp"
"runtime/debug"
"strconv"
"strings"
"sync"
)
// Version is the Steward version (the VERSION file).
var Version = "0.1.0-dev"
// Tag is the release tag the build is of ("" when it isn't a release).
var Tag = ""
// Commit is the git commit the build is of. It is read from the build
// information when not set at build time.
var Commit = ""
// Describe is 'git describe --tags --long' of the build's commit
// ("v0.2.0-rc.1-3-gca0f148b78b6"), set by the Makefile; it says how many
// commits a development build is past the last tag.
var Describe = ""
// Repo is Steward's source repository.
const Repo = "https://gitea.adbraun.lol/adam/steward"
// Build describes what a binary was built from.
type Build struct {
Version string `json:"version"`
Tag string `json:"tag,omitempty"`
Commit string `json:"commit,omitempty"`
Modified bool `json:"modified,omitempty"` // built with uncommitted changes
// Since is the last tag before a development build's commit, and
// Ahead how many commits the build is past it (0: the tag's commit,
// with uncommitted changes).
Since string `json:"since,omitempty"`
Ahead int `json:"ahead,omitempty"`
// Label is the short form to show: the tag of a release, otherwise
// the abbreviated commit (or the version when the commit is unknown).
Label string `json:"label"`
// URL is the release or commit in the repository.
URL string `json:"url"`
}
var info = sync.OnceValue(func() Build {
commit, modified := Commit, false
if bi, ok := debug.ReadBuildInfo(); ok {
for _, s := range bi.Settings {
switch s.Key {
case "vcs.revision":
if commit == "" {
commit = s.Value
}
case "vcs.modified":
modified = s.Value == "true"
}
}
}
b := describe(Version, Tag, commit, modified)
b.Since, b.Ahead = parseDescribe(Describe, b.Commit)
return b
})
// parseDescribe splits git describe --long output, if it is of commit.
func parseDescribe(d, commit string) (since string, ahead int) {
m := describeRe.FindStringSubmatch(d)
if m == nil || commit == "" || !strings.HasPrefix(commit, m[3]) {
return "", 0
}
n, _ := strconv.Atoi(m[2])
return m[1], n
}
var describeRe = regexp.MustCompile(`^(v.+)-(\d+)-g([0-9a-f]+)$`)
func describe(version, tag, commit string, modified bool) Build {
b := Build{Version: version, Tag: tag, Commit: commit, Modified: modified}
switch {
case tag != "":
b.Modified = false // the Makefile only sets Tag for clean trees
b.Label, b.URL = tag, Repo+"/releases/tag/"+tag
case commit != "":
b.Label, b.URL = short(commit), Repo+"/commit/"+commit
if modified {
b.Label += "-modified"
}
default:
b.Label, b.URL = version, Repo
}
return b
}
// Info describes this build.
func Info() Build { return info() }
// String is the version for logs and 'version' commands. Only a release
// build gives a version ("0.2.0"); any other build says it's a
// development build: "dev a1b2c3d4e5f6 (3 commits after v0.2.0-rc.1)".
func String() string { return Info().String() }
func (b Build) String() string {
switch {
case b.Tag != "":
return b.Version
case b.Commit == "":
// No git information (built from a source archive).
return b.Version + " (source build)"
}
s := "dev " + b.Label
switch {
case b.Since == "":
case b.Ahead == 1:
s += " (1 commit after " + b.Since + ")"
case b.Ahead > 1:
s += " (" + strconv.Itoa(b.Ahead) + " commits after " + b.Since + ")"
case b.Modified:
s += " (" + b.Since + " with uncommitted changes)"
default:
s += " (at " + b.Since + ")"
}
return s
}
// Short is the version for a User-Agent: the version of a release,
// otherwise the label ("a1b2c3d4e5f6").
func Short() string {
if b := Info(); b.Tag == "" && b.Commit != "" {
return b.Label
}
return Version
}
func short(commit string) string {
if len(commit) > 12 {
return commit[:12]
}
return commit
}