Skip to content

feat: add Snitchwatch bridge 0.1.1 system image candidate - #76

Merged
bearyjd merged 7 commits into
mainfrom
feat/snitchwatch-system-image
Oct 7, 2026
Merged

bearyjd merged 7 commits into
mainfrom
feat/snitchwatch-system-image

Conversation

@bearyjd

@bearyjd bearyjd commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

An opt-in SNITCHWATCH_BRIDGE=system image installs the authenticated Snitchwatch system bridge with its actual executable version set to 0.1.1. The image records the reviewed source revision and installed file hashes, provides root-only OpenSnitch IPC and protected GUI access, and includes read-only readiness checks plus transactional migration and rollback that preserve firewall policy.

The candidate uses source 5c2b44adece96008e973947a9551b700b8d8a15b, a separately reviewed OpenSnitch shutdown repair, and the GUI built with org.kde.Platform/x86_64/6.11. GUI authorization remains an explicit operator action. The existing published v0.1.1 release retains its original assets; new artifacts have a distinct system-candidate identity.

Validation includes bridge and GUI source tests, all four Snitchwatch CI jobs, clean reproducible bridge builds, reviewed GUI source/license archives, build-selector tests, and readiness/migration behavior tests. Final daemon, image smoke, first-boot, default KDE GUI, and migration/rollback VM evidence is summarized below. Runtime acceptance limits remain five seconds for fallback, two seconds for pending cleanup, and fifteen seconds for daemon stop.

Related source: bearyjd/snitchwatch#39

VM acceptance (2026-10-07)

Both candidates were built as clean rootful factory images and booted from fresh qcow2 disks under enforcing SELinux.

78be87b failed the cold-boot gate. In 2 of 7 boot-time starts opensnitchd lost one netfilter queue reader while the queue stayed bound, so new outbound connections hung (QueueBypass never applied). The patched C reader exited on any nfq_handle_packet() failure, which upstream ignores.

d96a7a5 fixes the daemon patch (now 19 files, 8d68ad9e…, reproducible binary 2cf22351…): it ignores per-message failures, restarts through the normal shutdown path if a reader still dies, and sizes the receive buffer for a full queued message. Red-then-green C/Go tests; independent code and security review approved.

d96a7a5 (image 63da3c01) passed:

  • first boot identity, DAC, fixture, warm and cold no-GUI fallback, eight timed daemon stops (~0.2 s, warning-free), foreign NFT, migration, refusals, token rotation;
  • 15/15 cold multi-user boots with no stalled queue; 5453 nft base-chain churns under traffic with no reader loss;
  • default KDE GUI with no Qt overrides: inline Allow, bridge-restart reconnect with the same GUI process, last-GUI fallback (HTTP 200 0.091 s after kill), unenrolled-user EACCES, root-only gRPC after enrollment; 0 AVC.

Not exercised: the reader-death fallback on the VM (unit-tested), a GUI Deny, a late verdict for a removed row. Open: a reboot-stop nfq_destroy_queue warning, a startup deliverPacket timeout accept, readiness flagging an empty drop-in directory, and the patch tests not running in CI (roadmap item 7). Details: docs/research/snitchwatch-system-bridge.md (Target-image validation).

CI has not yet run on d96a7a5/df1fdb1; the earlier green checks belong to 78be87b.

Refresh codemaps and the runbook with reviewed runtime, clean-build, and VM evidence. Preserve conditional GUI requirements, daemon teardown warnings, and supported-runtime and release gates.
Read empty systemd properties explicitly and verify omitted structured arrays through typed D-Bus replies. Accept only byte-pinned Fedora shutdown and Bazzite Flatpak baselines while retaining strict override and capability refusals.

Keep failed boot diagnostics and permit the exact system candidate banner tag in smoke checks. Verified 52 system and 8 legacy cases, independent review, and strict readiness in the disposable diagnostic container.
The shutdown patch ended the NFQUEUE reader whenever nfq_handle_packet()
failed. libnetfilter_queue reports any NLMSG_ERROR that way, including the
reply to a verdict for an entry the kernel flushed when another base chain
was unregistered at boot. The queue stayed bound to the daemon, so packets
were queued without verdicts and new outbound connections hung; bypass never
applied and Restart=always never fired. Reproduced in 2 of 7 cold boot-time
daemon starts on the target VM, confirmed by goroutine dumps (one of two
queue readers missing) and the unflushed EIO reader-exit message.

Ignore nfq_handle_packet() failures as upstream does. If a reader still
stops without a stop request, log it and leave through the normal shutdown
path with exit status 1 so systemd restarts a working daemon. Size the
receive buffer for a full queued message (4096-byte copy range plus
headers): a truncated message never gets a verdict and can fill the queue.

Adds a C reader fixture and Go tests (red before the fix), repins the
19-file patch, the pins digest and the patched-file count. The reproducible
daemon build is 2cf22351d645d7843b487d31dfb431d38b449aa0d4eadb13e518932d7dee4d02.
Independent code and security review approved the final patch.
…acceptance

The 78be87b candidate failed the cold multi-user no-GUI gate: in 2 of 7
boot-time starts opensnitchd lost a netfilter queue reader while the queue
stayed bound, so new outbound connections hung. d96a7a5 repaired the daemon
patch; its rebuilt candidate passed the enforcing-SELinux VM gates, including
15 clean cold boots, a base-chain churn stress test and default KDE GUI
startup, Allow, reconnect, last-GUI fallback and outsider refusal.

Record what was not exercised, the VM-only fixture steps, the open daemon
items, operator notes for the system candidate, and a roadmap item to run the
patch's tests automatically.
@bearyjd
bearyjd marked this pull request as ready for review October 7, 2026 23:42
@bearyjd
bearyjd merged commit b12f571 into main Oct 7, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant