{"id":591,"date":"2026-09-29T19:12:00","date_gmt":"2026-09-30T02:12:00","guid":{"rendered":"https:\/\/blog.canutethegreat.com\/?p=591"},"modified":"2026-11-09T01:31:54","modified_gmt":"2026-11-09T09:31:54","slug":"patronus-dev-log-3-back-in-september-with-43-red-ci-runs-and-no-green-ones","status":"publish","type":"post","link":"https:\/\/blog.canutethegreat.com\/index.php\/2026\/09\/29\/patronus-dev-log-3-back-in-september-with-43-red-ci-runs-and-no-green-ones\/","title":{"rendered":"Patronus dev log 3: back in September, with 43 red CI runs and no green ones"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Part 3 in the Patronus dev log series.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Backdated, written in November 2026 from git and CI records. <a href=\"https:\/\/blog.canutethegreat.com\/index.php\/2025\/12\/18\/patronus-dev-log-2-kubernetes-a-react-ui-and-a-rust-workspace-that-wouldnt-build\/\">Part 2<\/a> ended with nine months of silence.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I picked Patronus back up the same day as Horcrux, September 24, 2026. The first job was the same: make CI run. Patronus got a Rust CI workflow that day (fmt, clippy, tests, an eBPF check, a full-workspace build). It failed. Over September 24 to 30 the Forgejo record shows 57 runs: 43 failures, 7 cancelled, 7 skipped, 0 successes. Of those, <code>rust-ci.yml<\/code> had 42 failures.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first failures were the dull kind: a missing <code>libmnl-dev<\/code>, a missing <code>libelf<\/code>, no linker on the runner image, and a real bug. An eBPF map-create call took its name as <code>i8<\/code> and needed <code>u8<\/code>, which was blocking the detection and CNI crates from building at all.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Dockerfile again<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Same mistake as in Horcrux, found the same day. The Dockerfile had become a generic <code>FROM rust<\/code> build on a Debian slim image. The repo notes now say so, in short:<\/p>\n\n\n\n<pre tabindex=\"0\" class=\"wp-block-code\"><code>A generic FROM rust -&gt; cargo build -&gt; debian slim Dockerfile is wrong.\nIt crept in once and was fixed on 2026-09-24.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Patronus builds through real Portage against its own overlay. The ebuild kept breaking, in familiar ways: <code>virtual\/rust<\/code> doesn&#8217;t exist (same bug as Horcrux, the commit says so), acct-user and acct-group variable names were wrong, a USE flag was called <code>carp<\/code> in the code and <code>ucarp<\/code> in IUSE, the meta USE flags defaulted on with no sub-backend, and the ebuild forwarded cargo features that don&#8217;t exist (<code>aliases<\/code>, <code>tc<\/code>, <code>prometheus<\/code>). Building Rust from source inside the Docker build took 2 hours 45 minutes, so I switched to <code>dev-lang\/rust-bin<\/code>. And the Gentoo Docker build got capped at 60 minutes and made non-blocking while I sorted it out.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On the 29th the installer picked up root-on-ZFS, preferred when the ZFS tools are present.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Design decisions<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Gentoo and USE flags: Gentoo is the core design point. My reason is freedom to choose. USE flags come first because they let you pick which features (web UI, eBPF\/XDP, SD-WAN, detection, cloud integrations) get compiled in, and the repo notes call that the main advantage over pfSense and OPNsense. Hardware specific compiles are the second reason. A container build must pass USE flags through to <code>emerge<\/code> rather than compile a fixed set.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">rust-bin over source Rust: the from-source build took 2h45m (the commit&#8217;s number).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Architecture: the repo notes have one rule: one SQLite store as the single source of truth, one &#8220;Applier&#8221; per subsystem, one apply step at boot, and no extra in-memory list, fixture or config file that only one process knows about.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">State on September 30<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">57 runs, none green, and about 60 commits. The Gentoo build was non-blocking at the end of the week and still no run was green.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Other parts: <a href=\"https:\/\/blog.canutethegreat.com\/index.php\/2025\/10\/11\/patronus-dev-log-1-a-firewall-that-claimed-100-feature-parity-on-day-one\/\">Part 1<\/a>, <a href=\"https:\/\/blog.canutethegreat.com\/index.php\/2025\/12\/18\/patronus-dev-log-2-kubernetes-a-react-ui-and-a-rust-workspace-that-wouldnt-build\/\">Part 2<\/a>, <a href=\"https:\/\/blog.canutethegreat.com\/index.php\/2026\/10\/15\/patronus-dev-log-4-an-installer-test-that-failed-57-times-in-a-row\/\">Part 4<\/a>, <a href=\"https:\/\/blog.canutethegreat.com\/index.php\/2026\/11\/06\/patronus-dev-log-5-security-holes-netlab-and-the-0-2-0-release\/\">Part 5<\/a>.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>September 24 to 30, 2026: I restarted Patronus. Fifty-seven CI runs, 43 failures, no successes, and the same Dockerfile mistake as Horcrux.<\/p>\n","protected":false},"author":1,"featured_media":615,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,26],"tags":[366,377,164,373,291],"class_list":["post-591","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-software-engineering","tag-ci","tag-ebpf","tag-gentoo","tag-patronus-dev-log","tag-rust"],"_links":{"self":[{"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/posts\/591","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/comments?post=591"}],"version-history":[{"count":4,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/posts\/591\/revisions"}],"predecessor-version":[{"id":670,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/posts\/591\/revisions\/670"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/media\/615"}],"wp:attachment":[{"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/media?parent=591"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/categories?post=591"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.canutethegreat.com\/index.php\/wp-json\/wp\/v2\/tags?post=591"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}