Skip to content

sigwood v0.2.8

Latest

Choose a tag to compare

@helixmap helixmap released this 25 Jul 02:57

Added

  • The graph player shows byte flow as moving grain. Ribbons carry small
    particles drifting from source to destination - density and speed follow
    each flow's current rate, inside the same frozen layout. On by default for
    byte-active conn replays (where rate is a measured claim), off for
    count-only graphs, always toggleable (flow on|off), and the default
    respects reduced-motion preferences. Filter clicks now snap the scale
    instantly instead of gliding.

  • The graph player carries a scale gauge. A small bottom-left bracket shows
    what a ribbon's height is worth (200 B/s, 5k/s), reading the exact scale
    the ribbons are drawn with - so the gauge can never disagree with the
    picture. It breathes with the scale in fill, sits still in absolute,
    follows the bytes/conns metric, and rides into saved clips.

  • sigwood init offers to skip detectors you have no logs for. Decline a
    source during setup and the wizard now names the default-hunt detectors that
    would have read it and offers a one-keystroke detect exclusion (e.g.
    detect = "default, !beacon, !scan") - so a box without Zeek stops seeing
    per-run "conn.log not found" notes it can do nothing about. Re-running init
    after adding the source offers to lift the exclusion; a hand-written custom
    detect value is never touched, and declining the offer writes nothing.

  • Pick a graph by name: sigwood graph conn (also dns, pihole). Kind
    names select just those artifacts from configured sources; names compose
    (sigwood graph conn dns) and a single selected kind may stream to stdout or
    an exact --out file. Kind names and paths don't mix - a file literally named
    conn is reached as ./conn. With kinds selected, only those families are
    probed, so a broken or unreadable unselected source no longer fails the run.

  • Graph flow grain is bidirectional. Byte-active conn replays now show
    responder traffic as reverse grain - particles drifting destination-to-source
    in the source's color - split from forward grain by each flow's true
    responder-byte share (Zeek's resp_bytes, newly carried in the canonical
    connection schema). Ratios are exact at every aggregation tier - server
    folds and in-player rollups both sum bytes before dividing - so a
    download-heavy flow honestly shows mostly reverse grain. Ribbon shapes,
    counts, and saved-artifact geometry are unchanged; the optional direction
    ratio travels with clips, and graphs without responder data simply show
    forward grain as before.

  • The report says how it was made. Text and HTML/PDF reports now carry a
    provenance row - generated: <timestamp> · sigwood <version> - and, for CLI
    runs, as: <the exact command line> - so a saved report answers "which tool,
    which version, when, invoked how" by itself. The JSON feed carries both facts
    as run_summary.generated_at (ISO UTC) and run_summary.invocation
    (additive; no schema bump).

Changed

  • An "admin session" can no longer span days. Hosts with periodic privileged
    automation (a sudo cron under 45 minutes) used to chain their session
    open/close lines into one enormous "admin session" review unit - up to two
    weeks wide on long lookbacks - hiding unrelated findings under a wrong label.
    Session recognition now declines any candidate longer than 8 hours (measured:
    real interactive sessions top out well under 2 hours, automation chains start
    near a day), and the affected findings simply keep their own shapes. Genuine
    sessions, update runs, and reboot handling are unchanged.
  • Hardware-key logins and kernel dumps no longer flood the syslog report.
    A second calibrated drain3 mask recognizes space-separated hex-pair runs (four
    or more pairs - FIDO2/CBOR debug dumps, kernel oops Code: lines), so a dump
    that repeats at every login shares one template instead of minting a fresh
    "rare" burst each time. Measured on a month of real fleet logs: the per-login
    burst class disappears while every MEDIUM finding and every genuinely
    once-ever event is preserved. Colon-joined MAC addresses and ordinary
    two-pair text (dates, port 22 80) are never masked; raw log lines are
    displayed byte-for-byte as always.
  • Syslog rows share one grammar. Burst spans render through the same compact form
    as family and transaction rows (with a new honest seconds tier below one minute -
    45s, not 0m), burst counts pluralize properly, and a transaction row now leads
    with its rare-line magnitude (19 rare lines) instead of the internal
    "member findings" phrase; the member count remains in evidence and JSON. Program
    mixes de-duplicate case variants for display (CRON, cron reads once, first
    spelling kept) - counts and machine output keep both.
  • The report header names sources, not glob patterns. The records: line reads
    12,345 syslog · 90,000 Zeek conn instead of 12,345 *.log* · 90,000 conn*.log*.
    The JSON feed additively carries the mapping as run_summary.record_labels
    (no schema bump); record_counts keys are unchanged.
  • Syslog review units roll up only when it pays. Family and burst folding now
    starts at four rare lines (previously two and three): below that, a summary row plus
    its expansion costs as much space as the lines themselves, so one to three rare
    lines surface individually. Recognized transactions still group from two findings -
    their label carries meaning beyond compression. Tunable as before via
    family_min_size / burst_min_size under [detectors.syslog].
  • Capsule summaries are tokens-only. The per-template digest lines inside family
    and burst rows are gone; the tokens: scent line may now span up to two lines, and
    opening a row's sample always reveals something new (the raw lines). rsyslog's
    #011/#012/#015 whitespace escapes read as separators while distilling tokens,
    so multi-line commands no longer render as glued tokens; raw lines stay verbatim.
  • Transaction rows in HTML expand straight to their raw log lines. The
    severity-pill toggle on an admin-session or update-run row now opens the members'
    sampled raw lines under thin per-member separators instead of one-line member
    summaries; JSON member records additively carry the same bounded samples, in
    chronological member order. Separators name severity, program, and line count
    only - internal grouping vocabulary no longer appears in any output - and a JSON
    member record carries a tier key only when the member really is a family or
    burst rollup (a plain rare line omits it). Log content is never rewritten:
    whatever words an operator's own lines contain render verbatim.
  • Graph artifacts open in the full three-column view. The player's view
    segment now lands with the middle tier on - services for conn, resolvers or
    query types for dns, dispositions for Pi-hole - matching how the graph is
    actually read; one click on hosts collapses it. The segment labels name the
    view states plainly. Clips inherit the new default; previously saved artifacts
    are unchanged (they are self-contained).
  • graph windows a directory like the hunt does. A bare sigwood graph
    against a Pi-hole (or any flat) directory now reads the last default_window
    of available data - peeking rotation files' first timestamps and skipping the
    rest instead of decompressing the whole archive - and the artifact discloses
    the window. --all, explicit timeframes, and single named files behave
    exactly as before.
  • warn_above = 0 now disables the large-dataset prompt. Previously 0 meant
    prompt before analyzing any amount of data; it now switches the advisory prompt
    off entirely - the config-side equivalent of passing -y every run, suited to
    cron and other unattended schedules. Set a small positive value to keep an
    aggressive prompt.
  • The report wordmark matches the graph player's brand mark. The sigwood
    token in the HTML/PDF report header now renders in the same serif face and
    light/dark color pair as the graph player's wordmark; the · threat hunt
    tagline keeps its bold sans treatment. A parity test pins both artifacts to one
    identical font stack and color pair so the two marks cannot drift apart.

Fixed

  • A reboot is never mislabeled an "update run", and its rebooted marker can
    no longer vanish from the report.
    On RHEL-family hosts a normal boot emits
    lines that satisfy the update-run grammar (dracut, the auditd stop/start pair,
    SELinux policy load), so a routine reboot could form a medium "update run"
    review unit that swallowed the reboot itself. Update-run recognition now
    ignores anchors inside a detected boot window (measured bounds), and a
    rebooted burst is never claimed by any review unit - the reboot always
    stays a visible row, including after a genuine update-then-reboot.
  • Graph flow particles read as streams, not stripes. Same-moment spawns used
    to move in lockstep and bunch into vertical bands that marched across a
    ribbon, most visibly after a filter click. Each particle now carries its own
    slight speed variation, a restarting ribbon fills uniformly along its length,
    and the round dots are replaced by short motion streaks that follow the
    ribbon's curve - longer for faster flow - with a gentle brightness shimmer
    lifted off the ribbon color. Particles now pause with playback: a paused
    frame is fully still, and a filter click while paused recomposes the grain
    without motion. Flow direction, the toggle and its defaults, and saved
    artifacts are unchanged.
  • The graph header now counts the files that fed the graph, not the archive it
    scanned.
    The source cell used to report every file discovered under the
    source directory (+ 294 others on a large rotation archive) even when the
    rendered window drew from a handful of them. The loader now records each
    file's kept time span and the header names only the files whose data
    overlaps the final rendered window; saved clips keep the parent artifact's
    set. The live system journal never records file paths.
  • The HTML report now discloses an underfilled window like the text report.
    The HTML header's window row carries the same span parenthetical the text
    banner always had - the bare data span normally, and the
    (Xh data span in Yd window) disclosure when the loaded data underfills the
    requested lookback. The two surfaces share one formatter so they cannot drift.
  • Progress lines name the directory when file names repeat. A dated Zeek archive
    loads several files that share one rotation name, and the load narration used to
    render identical loaded conn.00:00:00-00:00:00.log.gz lines for all of them. When
    any file names in one load collide, every line now carries one parent-directory
    component (loaded 2026-05-01/conn.00:00:00-00:00:00.log.gz), and a corrupt-file
    warning names the same disambiguated file. Loads without repeated names render
    exactly as before.