LUCIANO CARRIZO
All articles Programming

The CI I inherited had never been green

A fork brings the code, the license, and the history. It also brings broken CI, and nobody tells you until you open the first PR.

When I forked winfunc/opcode to build opcode-lucho, I assumed the boring part was already solved: the repository came with five GitHub Actions workflows (pr-check.yml, build-test.yml, build-linux.yml, build-macos.yml, release.yml), so I thought I only had to start opening PRs and let the checks do their job.

pr-check.yml failed on every single one of my first PRs. Neither cause had anything to do with my code.

Cause one: system dependencies that were never installed

The error was Package glib-2.0 was not found in the pkg-config search path. Tauri needs system dependencies to compile on Linux, and pr-check.yml never installed them on ubuntu-latest before running cargo check. The correct dependency list already existed in build-test.yml, in the same repository—it had simply never been carried over to the workflow that runs on every PR.

Cause two: cargo check needs a dist/index.html that tsc never produces

With the system dependencies fixed, pr-check was still red. The workflow ran bun run check, which in this repository means tsc --noEmit && cargo check. The problem lives in web_server.rs: it uses include_str! to embed dist/index.html into the binary through Tauri’s generate_context!. That file does not exist until the frontend is built—and tsc --noEmit does exactly what its name says: it type checks, but emits nothing. cargo check was looking for a file nobody had built yet.

The solution was to run bun run build before cargo check in the workflow, not afterward or in parallel.

A third finding while fixing the first two

build-test.yml—the workflow that builds the app on all three platforms—had never run at all: it targeted the main and develop branches, which do not exist in this fork (the flow here is task branch → PR → devmaster). This was not a subtle configuration bug; it was an entire workflow pointing nowhere.

With both pr-check causes fixed and the build-test branches corrected, pr-check now passes in 7m51s and build-test builds all three platforms without intervention.

What this exposed: red checks blocked nothing

While investigating why CI had never been green, I found something worse: because there was no branch protection, a PR had once been merged with red checks. CI could fail as loudly as it wanted, and nothing stopped anyone.

I added rulesets to master and dev with no bypass—not even for me as admin. They require an open PR and a green bun run check before merging, and block force pushes and branch deletion. I verified them by pushing directly to master: GitHub rejected it with GH013.

That revealed the twist I did not expect: protection rulesets are unavailable for private repositories on GitHub Free. The repository was still private at the time, and the API returned a 403 with a direct message: “Upgrade to GitHub Pro or make this repository public.” There is no way to protect a branch in a private repository without paying. The sequence was forced into the opposite of what I would have chosen beforehand: make the repository public first, then close the protection gap.

Forking a large codebase is not only inheriting code. It is inheriting its infrastructure too, including all of its silent breakage. Nobody warns you—you discover it by opening the first PR.

Next step

The article explains the decision. The technical case shows the code.

The opcodelucho project is documented end to end: architecture, decisions, and what remains unfinished.

or directly → LuchoC.dev@gmail.com