Skip to content

fix(ci): piping into grep -q is broken under pipefail#44

Merged
vietanhdev merged 2 commits into
mainfrom
fix/release-verify-sigpipe
Jul 20, 2026
Merged

fix(ci): piping into grep -q is broken under pipefail#44
vietanhdev merged 2 commits into
mainfrom
fix/release-verify-sigpipe

Conversation

@vietanhdev

Copy link
Copy Markdown
Owner

The v0.2.0 release failed. build (aarch64) failed its own verification, release was skipped, nothing published — the gating held, but the check was wrong.

dpkg-deb: error: tar subprocess was killed by signal (Broken pipe)
::error::.deb does not ship /usr/bin/thinkutils

The file was there. grep -q exits the instant it matches, dpkg-deb takes SIGPIPE writing the rest of the listing, and pipefail propagates that non-zero status — so finding the file is what made the check report it missing.

Why this matters more than a red run

  • Not architecture-specific. x86_64 passed on the same commit; ARM lost a race. Latent in release.yml since before this session; it would have failed an x86_64 release eventually.
  • Fails in the dangerous direction too. The same race resolving the other way passes a package nobody verified. A timing-dependent check isn't a check.

The obvious fix does not work

Capturing the output first and piping that into grep -q fails identically — printf takes the SIGPIPE instead. I found that by testing every formulation rather than reasoning about it:

form result
producer | grep -q P MISSING (bug)
capture, then pipe into grep -q MISSING (bug)
grep -q P <<<"$contents" found
producer | grep P >/dev/null found (no -q, so grep reads to EOF)

Uses the herestring form, and lists the .deb once into a variable instead of twice.

Same shape elsewhere

  • publish-copr.ymlcopr-cli list | grep -qE (external command, same exposure)
  • test-gui-packages-docker.sh ×2 — small strings so it works in practice, but a false negative there fails a release for no reason

No pipes into grep -q remain in any workflow or script.

134 tests pass. After this merges, v0.2.0 gets re-tagged and re-released.

The aarch64 release build failed its own verification with

  dpkg-deb: error: tar subprocess was killed by signal (Broken pipe)
  ::error::.deb does not ship /usr/bin/thinkutils

The file was there. grep -q exits the instant it matches, dpkg-deb takes
SIGPIPE while writing the rest of the listing, and pipefail propagates
that non-zero status -- so FINDING the file is what made the check report
it missing. Failing in that direction is the dangerous one: the same race
resolving the other way passes a package nobody verified.

Timing-dependent, not architecture-specific. x86_64 passed on the same
commit; ARM lost the race. It has been latent in release.yml since before
this session and would eventually have failed an x86_64 release too.

Verified which formulations actually survive, because the obvious fix
does not -- capturing the output first and piping THAT into grep -q fails
identically, since printf takes the SIGPIPE instead:

  producer | grep -q PATTERN            MISSING (bug)
  capture, then pipe into grep -q       MISSING (bug)
  grep -q PATTERN <<<"$contents"        found
  producer | grep PATTERN >/dev/null    found   (no -q, so grep reads to EOF)

Uses the herestring form, and lists the .deb once into a variable rather
than twice. Applied to the same shape in publish-copr.yml (copr-cli list)
and the two in the launch test, where a false negative would have failed
a release for no reason.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 20, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
thinkutils 6cf5f81 Jul 20 2026, 06:02 AM

…iled

Two problems, both found by dry-running the workflows before using them.

Neither workflow checked out the tag it was asked to publish. checkout
had no ref, so it took the default branch and then labelled the result
with the requested version. Publishing main's spec, PKGBUILD and
manifests under an older tag's version number is wrong on its own; it
surfaced here as COPR fetching a v0.2.0 tarball during a run explicitly
asked to publish 0.1.10, because main had already been bumped.

The tag check used the 'origin' alias, which depends on the checkout's
local git config being readable. Inside a container it is not, so:

  fatal: 'origin' does not appear to be a git repository
  ::error::v0.1.10 does not exist on origin - push it before publishing

The tag existed. The step reported the wrong cause entirely, and would
have sent someone looking for a missing tag rather than a git config
problem. Fedora's container tolerated it and Arch's did not, so this
would have looked arch-specific too.

Both now resolve the tag against an explicit repository URL, which needs
no local config, and check out that tag.
@vietanhdev
vietanhdev merged commit 5ab1234 into main Jul 20, 2026
11 of 12 checks passed
@vietanhdev
vietanhdev deleted the fix/release-verify-sigpipe branch July 20, 2026 06:17
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