summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-07-01Document abbreviate_rule's nat/rdr blind spot and ddclient's log gapHEADmasterbatsumaru
From a fresh-agent review of AGENTS.md against two hypothetical tasks: - abbreviate_rule() in pf.sh has only ever been developed/tested against filter-rule (-sr) syntax, despite also running on -sn (nat/rdr) output. It degrades safely (unshortened passthrough) but a new nat/rdr rule shape isn't guaranteed to compress as tightly - noted both in the code comment and in AGENTS.md's compression writeup so this doesn't need rediscovering. - ddclient logging isn't enabled on the box, so "is the last DNS update actually succeeding" can't be built by tailing a log that doesn't exist - it'd need the cache file or a public-IP comparison instead. Recorded in AGENTS.md's topology section since ddclient.sh currently only checks the process is running, not update success. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Remove dangling reference to a handover doc that isn't in the repobatsumaru
The original handover was only ever pasted into a conversation, never committed as a file - a fresh agent session has nothing to "see." State the project's origin and goal directly instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Expand AGENTS.md: topology, one-line-fit preference, real-time triggersbatsumaru
Homelab topology: pulled the infrastructure context from the original handover doc (FreeBSD version, WireGuard/Caddy/ZFS/jail network layout) that isn't otherwise captured now that check.sh is gone. Design preference: documents "rows should fit on one line" as a standing preference (not a one-off ask), with checks/pf.sh's abbreviate_rule() development as the worked example of how to compress long/variable-length output - strip ruleset-specific boilerplate, verify symbol choices against the font's actual glyph coverage, prefer legible bracket-letter tags over clever-but-obscure unicode when a distinction has real meaning, and always confirm via a rendered preview rather than eyeballing character counts. When cron + static HTML stops being enough: concrete signals (need for alerting, history/trends, sub-minute or push-based updates, render time approaching the cron interval) that mean this architecture is being outgrown, so a future ask crossing one of these gets flagged explicitly instead of worked around within the current design. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Add AGENTS.md for cross-session agent contextbatsumaru
Covers what a fresh session needs that statuspage/README.md doesn't: the Windows-checkout-vs-FreeBSD-runtime split (nothing here actually executes the check scripts' real commands), the git push/pull deployment loop, the core.fileMode/pre-commit-hook setup, and five gotchas hit and fixed this session (usec/sec substring match, ntpq's "+" prefix, grep -c's exit-1-on-zero, Windows ln -s on directories falling back to a copy, font glyph coverage). CLAUDE.md is a pointer to AGENTS.md rather than a symlink or a duplicate copy - this checkout can't reliably create real symlinks (same root cause noted in AGENTS.md itself), and a stale copy would silently drift out of sync as AGENTS.md changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Fix clock offset extraction dropping positive valuesbatsumaru
ntpq's "rv 0 offset" prefixes non-negative offsets with an explicit "+" (e.g. "offset=+0.030208"), which wasn't in the sed capture class ([-0-9.]). Since the capture group is starred, the regex still "matched" with an empty capture instead of failing outright, silently producing "no response" for every positive/zero offset while negative ones (which do use "-", already in the class) worked fine. Confirmed against the real box: earlier renders with negative drift worked, then it started showing "no response" once the drift crossed zero. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Distinguish pf state-tracking modes with bracketed letter tagsbatsumaru
Previously "keep state" and "modulate state" both collapsed to the same generic "[state]" tag, losing a real distinction: modulate state hardens TCP ISN generation and synproxy state (not handled at all before) proxies the handshake against spoofed SYN floods - neither is just "some tracking is happening." Now [N]/[K]/[M]/[S] map to no/keep/ modulate/synproxy state respectively, documented in a comment since the mapping isn't self-evident without pf.conf familiarity. Considered thematic unicode symbols from the font's supported blocks (Mathematical Operators, Geometric Shapes) instead, but a bracketed letter is unambiguous without a legend - a clever but obscure glyph isn't actually more compact once you factor in "what does this mean." Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Sort pf rules by interface, iconify from/to, drop redundant nat prefixbatsumaru
Filter rules now sort by (interface, in-before-out) rather than pfctl's raw eval order, which just reflects pf.conf's authoring order and reads as arbitrarily interleaved (an "out" rule sandwiched between unrelated "in" rules for the same interface). Display-only reorder - pf's actual evaluation order and quick/first-match semantics on the box are untouched, only the informational listing is re-sorted. Generalized the "from X to Y" abbreviation beyond the from-any-to-any- port special case, and replaced pfctl's own "->" (nat rewrite target) with the unicode arrow for consistency with the in/out arrows already in use. Also dropped the "nat: " prefix, which was redundant with the rule text already starting with "nat". Applied the same "->" -> "→" consistency swap to jails.sh's http child-row label. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Abbreviate pf rule text so rows fit the column without wrappingbatsumaru
pfctl's verbose syntax (flags S/SA, quick, from any to any port = X, proto tcp/udp/icmp) was overflowing the .section column width and wrapping mid-rule. abbreviate_rule() in pf.sh strips the near- universal boilerplate tokens on this ruleset and swaps in/out for arrows - cuts each rule to roughly 35-45% of its original length. Deliberately not a real pf syntax parser: it's a handful of targeted sed substitutions, so a rule shape it doesn't recognize just passes through unshortened rather than mangling. Only uses the Arrows block (confirmed shipped in the scientifica font) - avoided Dingbats (checkmark/X) since that block isn't included in this font. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Add scientifica bitmap font and wire it into the status pagebatsumaru
Bundle scientifica.ttf/Bold/Italic in statuspage/fonts/ (dropped the .bdf/.otb variants - those are X11/console bitmap formats, browsers can't load them via @font-face). Mark font extensions as binary in .gitattributes so git never attempts CRLF conversion on them. render.sh now symlinks fonts/ into the Caddy-served output directory on every run (idempotent) since Caddy serves /usr/local/www/status, not this checkout - the font file has to physically exist next to index.html for the browser to fetch it. Also: fixed bad kerning/cramped line spacing from an earlier attempt at applying the font's recommended Terminal.app settings (which don't translate 1:1 to CSS), and added a hanging indent (.label class, text-indent + padding-left) so long wrapped label text - notably pf.sh's rule listing - aligns under the label instead of the status square when it wraps to a second line. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Say "never scrubbed" instead of "unknown" for pools with no scan historybatsumaru
Confirmed against the real box: a pool that's never had a scrub or resilver has no `scan:` line in `zpool status` output at all - it's not omitted due to a parsing bug, there's just nothing to report yet. "unknown" wrongly implied a parse failure. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Fix uptime to include hours/minutes, add a purple/gold themebatsumaru
hw.sh's uptime was parsed from `uptime`'s text output, which cut off at the first comma - dropping the H:MM part entirely. It also never actually rolled over to months/years for long uptimes (FreeBSD's uptime just keeps growing the day count). Replaced with a direct `sysctl kern.boottime` computation for a fully deterministic "Nd Hh Mm" format. Caught a real bug along the way: the first attempt at the sed extraction grabbed `usec` instead of `sec`, since "usec" contains "sec" as a substring and the pattern wasn't anchored tightly enough. render.sh's palette now uses purple/lavender for headings and borders and a gold accent (title underline, value-column text), taking cues from reference character art. The green/yellow/red/gray status squares are untouched - they carry semantic meaning the color scheme shouldn't interfere with. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Lay sections out in a multi-column flow instead of one long columnbatsumaru
pf.sh's rule listing made the page noticeably taller without using any of the available width. Wrap each section in a .section block and the whole set in a .cols container using CSS multi-column layout (column-width: 380px) - sections flow left-to-right/top-to-bottom across however many columns fit the window, each staying intact (break-inside: avoid) rather than splitting a table mid-page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Make the zpool check per-pool with capacity, scrub, and error statusbatsumaru
Replace the single "all pools are healthy" summary line with one row per pool (name, health, capacity) plus a scrub/errors row parsed from `zpool status <pool>`. A pool that's never been scrubbed but has no data errors still reports ok - lack of scrub history isn't itself a failure, only actual reported errors are. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Add pf visibility and a wg-quick watcher check, add a neutral row statusbatsumaru
checks/pf.sh reports pf enabled/disabled, state table usage (warn/down as it nears the configured limit), and the loaded filter/nat rule count, then lists each active rule as its own row for at-a-glance visibility into what's actually being enforced. Those rule rows use a new "info" status (gray square) rather than "ok" - they're not a health check on any individual rule, so a green square there would misleadingly imply otherwise. render.sh maps info -> gray; anything else still falls back to red. checks/wg-watcher.sh checks the route-monitor process wg-quick spawns to react to WAN interface/address changes - it isn't rc.d-managed, so there's no `service status` for it, hence the new proc_running helper in lib/common.sh (pgrep -f based). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Document the core.hooksPath setup for new clonesbatsumaru
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Mark .githooks/pre-commit itself executablebatsumaru
It doesn't match the *.sh glob the hook fixes up, so it committed as 100644 in the previous commit - harmless on this Windows checkout, but a fresh clone on a real Unix filesystem would get it non-executable and the hook would silently never run. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Add ntpd/clock-sync check and a pre-commit hook for exec bitsbatsumaru
checks/ntpd.sh reports whether ntpd is running and whether the clock's offset is within tolerance (ok <50ms, warn <200ms, down beyond that or if ntpq doesn't respond) - clock drift is a silent failure that otherwise only surfaces later as TLS handshake failures or misleading cross-jail log timestamps. Also add .githooks/pre-commit + core.hooksPath, since this checkout is on Windows where core.fileMode is false (the filesystem doesn't reliably preserve the executable bit) - without it, a plain `git add` on a new check script silently stages it as non-executable, and render.sh skips non-executable files with no visible error. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Auto-discover jails and add WireGuard peer info to status pagebatsumaru
Replace the per-jail check scripts with checks/jails.sh, which lists running jails via jls and resolves each one's IPv4 (falling back to jexec+ifconfig for VNET jails, which don't set the ip4.addr jail parameter). New jails now show up without adding a script; the trade-off is a stopped jail just disappears rather than showing down, since jls only lists what's running. checks/wireguard.sh now also reports each configured peer's allowed-IP and time since last handshake, parsed from `wg show wg0 dump`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Mark statuspage shell scripts executable in gitbatsumaru
core.fileMode is false in this repo (Windows checkout), so the earlier commit recorded every checks/*.sh, lib/common.sh, and render.sh as 100644. render.sh skips non-executable files silently, so without this the deployed page would render with zero rows. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01Split monolithic status check.sh into modular check scriptsbatsumaru
Replace the single-file prototype with independently-addable check scripts (checks/*.sh) that each emit JSONL rows, a shared helper lib, and one orchestrator/renderer (render.sh) that groups rows by section and writes the static status page. A broken check script now shows up as a down/warn row instead of crashing the whole render. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>