GitHub Actions CI for the polymarket_fetch Rust workspace. It had been red on every push since 2026-05-19; as of 2026-05-22 it is fully green. This note records what was broken and the fixes — most are reusable gotchas.
The headline lesson
Pin the Rust toolchain in rust-toolchain.toml. A floating channel = "stable" means the CI runner picks up whatever the newest stable is, while the local dev machine sits on an older release. Newer clippy ships new lints, so code passes cargo clippy locally and fails the same check in CI. That skew is exactly why CI “kept failing” for no obvious reason. rust-toolchain.toml is now pinned to 1.95.0 — bumping it is a deliberate, reviewed edit, not a drift.
What was failing
fmt
Unformatted code. Fixed with cargo fmt --all.
clippy
CI ran clippy from the latest stable (1.95.0); the local machine was on 1.91.0. Lints that only exist in newer clippy — use_self, while_let_loop, unnecessary_sort_by — passed locally and failed in CI. Fixed the lints, then pinned rust-toolchain.toml to 1.95.0 so local and CI use an identical compiler and lint set.
cargo-deny
Three separate problems in the deny job:
-
Docker action couldn’t honor the toolchain file.
EmbarkStudios/cargo-deny-action@v2runs in an Alpine/musl container. It readrust-toolchain.tomland tried to use an uninstalledstable-x86_64-unknown-linux-musltarget. Fix: dropped the Docker action. The deny job now runs on a plainubuntu-latestrunner withtaiki-e/install-action@cargo-denyfollowed bycargo deny check. -
Wildcard path dependency flagged. cargo-deny rejected the internal path dependency as a wildcard. Fix: set
allow-wildcard-paths = trueindeny.tomland setpublish = falseon the two binary crates — cargo-deny only permits wildcard path deps when the crate is not published. -
Two RUSTSEC advisories.
rustls-pemfile(unmaintained) andtokio-tar(vuln) were both flagged. Both entered the graph only throughtestcontainersdev-dependencies. Rather than suppress them with an ignore list, bumpedtestcontainers0.23 → 0.27 andtestcontainers-modules0.11 → 0.15, which dropped both crates from the dependency graph entirely.
Docker build
Added a multi-stage Dockerfile that builds the lag-probe binary on top of a slim Debian runtime, plus .github/workflows/docker.yml which builds the image on every push.
Image push is intentionally disabled
docker.ymlruns withpush: false. A registry hasn’t been chosen yet — GHCR vs Google Artifact Registry. Both enablement paths are written into the workflow as comments, ready to uncomment once the call is made.