← all benchmarks

TrueMend vs. actionlint on GitHub Actions

TRUEMEND
19.5%
ACTIONLINT (ROUND 1)
40.0%
CONFIRMED · RIVAL NOT RE-RUN

Round 1’s 11.6% moved to 19.5% on a fresh, differently-composed pool; the round-1 file-type-gate fixes were re-verified and hold. Real-rate more than doubled, 17.0% to 40.3%. actionlint’s 40.0% is its round-1 number, and 19.5% is above our own bar. Both disclosed.

Round 2, a fresh full-pool sample: TrueMend 19.5% wrong-match against actionlint's round-1 40.0% (not yet re-measured this round). The wrong-match number moved on a smaller, differently-composed sample, not a reversal of round 1's fixes — real-rate more than doubled, 17.0% to 40.3%, the more meaningful signal this round.

actionlint is the purpose-built, single-ruleset linter for GitHub Actions workflow YAML — a corpus of 165 real workflows, flattened from eleven benchmark repos' .github/workflows/ directories, gave us a fair fight on its home turf.

The baseline was a confirmed loss

First measurement: TrueMend 55.7% wrong-match vs. actionlint's 44.4% — independently judged, not self-reported, and a clear loss. We published that number to ourselves before touching anything, the same discipline as every other campaign in this ledger.

Root cause: two detector families that don't belong in this file type

The single biggest lever, by far: 66 Kubernetes detectors and 24 Docker Compose detectors had no file_content_requires gate, so they fired on a GitHub Actions workflow's matrix.image:, container:, and services: blocks as if those were real Kubernetes manifests or Compose files — k8s-kubelinter-no-service-account alone went 8-for-8 wrong, every hit on a matrix.image: line that isn't a Kubernetes resource at all. Adding apiVersion: and (?m)^services: content gates before those detectors fire silenced 496 false positives outright — 1,079 findings down to 575 — with no loss of recall on files that are actually Kubernetes or Compose manifests.

Seven more detectors had a second, distinct problem: a premise that simply doesn't hold for a workflow trigger context. yaml-github-actions-secrets-plaintext was flagging default values like POSTGRES_PASSWORD: postgres that are container bootstrap conventions, not leaked secrets. ci-token-write-permissions treated any write-scoped permission as broad when only contents: write specifically is the risky one. Four detectors — checks for status checks, PR comments, conditional gating, and environment protection — can't actually be verified from the trigger event alone, so we disabled them as premise errors rather than keep a claim we couldn't back. One more got its Dockerfile anchor narrowed, and a matrix-include threshold got raised to reduce noise on small, legitimate matrices.

Round 1 result — a 29-point swing

TrueMend: 11.6% wrong-match. actionlint: 40.0%. 112 TrueMend findings and 35 actionlint findings, judged blind, same-session head-to-head. Worth-fixing narrowed from the baseline's 3.7%/30.6% gap to 17.0%/25.7% — closer, though still trailing.

What we weren't claiming in round 1

actionlint's expression, action, and syntax-check rules catch real workflow-expression correctness bugs — invalid property references, deprecated action versions — that a line-scan detector can't structurally express without a full workflow-expression AST. The same shape of gap shows up in the C# campaign's XML-doc case. In round 1, TrueMend won the headline wrong-match metric decisively; actionlint still found more genuinely worth-fixing correctness bugs on this corpus, and we said so rather than only publishing the number that flattered us.

Result — round 2, a fresh full-pool sample

TrueMend: 19.5% wrong-match. actionlint: 40.0% — round 1's number, carried forward, not re-measured this round. A parallel fix pass targeted the top wrong-match categories still open after round 1, then a fresh, from-scratch full-pool blind sample re-certified the result: 77 TrueMend findings judged. Four more categories fixed this round: devops-hardcoded-secret (well-known CI credential literal exclusion), continue-on-error (outcome-check negation logic), ci-no-release-please (release-event gate added), and a second pass on ci-token-write-permissions — round 1 fixed the broad-write-scope premise, round 2 added a push/commit-bot and reusable-workflow exclusion the first pass didn't cover. A new regression test file, tests/regression/test_ghactions_fp_regression.py, locks in all four — 10/10 passing.

RoundTrueMend wrong-matchactionlint wrong-matchReal-rateSample
Round 1 (2026-07-08)11.6%40.0%17.0%112 TrueMend / 35 actionlint judged
Round 2 (2026-07-28)19.5%40.0% (round-1 number, not re-measured)40.3%77 TrueMend judged, fresh full-pool sample

The wrong-match number moved from 11.6% to 19.5% — worse on the raw figure. That's the honest number, and it's not a reversal: round 1's fixes were independently re-verified this round and still hold. What moved is sample composition — round 2 is a smaller, differently-composed fresh pool (77 judged vs. 112), pulling from parts of the detector surface round 1's sample didn't touch, the same pattern seen across every re-certified target in this sweep (Bash, Java, Go, SCSS). The more meaningful signal this round is real-rate: worth-fixing more than doubled, from 17.0% to 40.3%.

Still open

actionlint has not been re-run this round — a true apples-to-apples round-2 comparison against a fresh actionlint measurement doesn't exist yet. TrueMend's round-2 wrong-match, 19.5%, remains above the 10% gold-standard bar this ledger holds every target to. Both are open, not closed.