6.4 KiB
6.4 KiB
To Do
Planned work, in order of priority. Each item names what to build, how it fits the existing seams, and how to verify it. Finished items move to the design doc they belong to.
1. Network access control (ACL)
The seam exists: internal/netacl wraps each listener's socket before TLS,
reads the PROXY header of the L4 proxies proxy_from lists, and the acl
block's allow and deny refuse the client by address
(Security). Every limit except SCRAM throttling
is still global.
1.1 Per-client limits
- Generalize the SCRAM limiter in
internal/authz/scram.go(token bucket per key, bounded table that fails closed, idle sweep, IPv6 per /64 viathrottleKey) into the shared per-key limiter. One mechanism (AGENTS.md): SCRAM throttling then uses it too. - Keys in the
aclblock:max_connections_per_clienton every listener (concurrent connections per client), applied by the netacl listener after the rules.requests_per_second_per_clienton HTTP listeners (ingest, stream and status requests).
- A full table refuses new clients and counts them in
acl_limited, besideacl_deniedandacl_proxy_headers. - Later: per-identity limits once a peer is authenticated (the mtls plan's deferred item 2), keyed by identity instead of address.
1.2 Address rules for forwarded clients
- In HTTP proxy mode,
X-Forwarded-Foris applied byauthz.ClientAddrafter the connection-level decision, so rules for forwarded HTTP clients belong in a second, request-level check there, reusing the compilednetaclrules.authz.parseProxiesthen takes netacl's address-or-CIDR parsing too.
1.3 Verification
- Go tests, one per rule: the per-client connection cap; the request rate; the limiter table failing closed; a forwarded client refused by the rules.
test/acl-test.shadds per-client connection caps, behind its stub proxy too.
2. Packaging: AUR, FreeBSD ports, Debian
The foundation exists:
- The
lwbinary name, free in Arch (official repositories and AUR), Ubuntu 24.04 and 26.04, and the FreeBSD 15.1 ports tree. - The canonical module path
github.com/lixenwraith/logwisp, whichgo install, FreeBSD'sUSES=go:modulesand Debian's dh-golang expect. make installwithDESTDIR,PREFIXandSYSCONFDIR.- The
doc/lw.1manual. - Service files in
deploy/package/: systemd unit, sysusers, tmpfiles and the FreeBSD rc.d script. - Skeletons in
deploy/package/arch/anddeploy/package/freebsd/.
What remains. Steps 1 to 3 are the maintainer's: they need push rights and an identity, and both skeletons download the tagged source.
- Tag the release on the merged main commit,
vX.Y.Z:git tag -a vX.Y.Z -m vX.Y.Z # git tag -s signs it with your key git push origin vX.Y.Zmakethen stampsvX.Y.Z(fromgit describe), andgo install github.com/lixenwraith/logwisp/cmd/lw@vX.Y.Zworks.- A GitHub release for the tag is optional; the tag alone serves
archive/vX.Y.Z.tar.gz, which the PKGBUILD downloads.
- Arch (AUR),
deploy/package/arch/PKGBUILD:pkgver=X.Y.Zand the# Maintainer: Name <email>line.updpkgsums(pacman-contrib) replacessha256sums=('SKIP')with the tarball's checksum.namcap PKGBUILD, thenmakepkg -si(builds, runscheck(), installs), thenmakepkg --printsrcinfo > .SRCINFO.- Push
PKGBUILDand.SRCINFOtossh://aur@aur.archlinux.org/logwisp.git; optionally alogwisp-gitpackage built from the main branch.
- FreeBSD,
deploy/package/freebsd/(sysutils/logwisp):DISTVERSION=X.Y.ZandMAINTAINER=your address.make makesumwritesdistinfo: the module zip that the Go proxy serves forGO_MODULEat the tag.- The
logwispuser needs an ID registered in the ports tree. Take a number below 1000 that is free in both/usr/ports/UIDsand/usr/ports/GIDs, and add to the same patch:UIDs: logwisp:*:NNN:NNN::0:0:LogWisp daemon:/nonexistent:/usr/sbin/nologin GIDs: logwisp:*:NNN: portlint -AC,poudriere testporton 14.x and 15.x jails, then a Bugzilla report with the port directory and the UIDs/GIDs diff.
- Debian:
- Debian policy wants every Go dependency packaged; the four
lixenwraithlibraries are not. - Either package them too (dh-golang), or start with an
.debbuilt by the Makefileinstalltarget (nfpm ordpkg-deb) and a PPA, and move to the archive later.
- Debian policy wants every Go dependency packaged; the four
- Shell completion for bash, zsh and fish, installed by
make install. - A packaging CI job: build the AUR package in an Arch container and the port
in a FreeBSD VM, run
lw --versionandmake image-check.
3. Follow-ups
Smaller items found along the way; each is independent of the ACL.
- A late browser sees no backlog: the
httpsink keeps none, so the viewer shows entries from when it connects. A bounded replay (areplay_linesoption, sent afterevent: connected) would fill it. The viewer also hides a503frommax_connectionsbehind "retrying"; the status JSON it already fetches could name it. - Level detection.
source.ExtractLogLevelneeds a delimiter after the name (ERROR:,[WARN],INFO), sowarning disk fullorDBG xget no level, hence no color. Match the names as words, as the console sink's painter does, with one table for both. - Command line:
- a positional word at the top level (
lw tail,lw -t FILE) still reaches config with an unclear message; name it ("unexpected argument X; the file is -c FILE"); - Go's flag errors keep single dashes ("flag needs an argument: -u");
- an unknown
--keyonly warns and then runs the stdin pipe; consider an error when stdin is a terminal; lw tls cert --hostcould become--hosts(keeping--host), to matchtls.hostsand the preset key;- top-level usage errors exit 1, subcommand ones 2.
- a positional word at the top level (
GET /favicon.icoanswers 404; the logo could serve as the icon once the pages' CSP allowsimg-src 'self'.- TLS: the generated-certificate key is one per process, so a pin taken from a
self_signedlistener also matches anissuerlistener of the same process; document it or key per listener. Pins are checked inVerifyPeerCertificate, which Go skips on resumption: guard it if a dialer ever keeps aClientSessionCache. core.ShutdownTimeoutis unused.