Files
DodoSSH/.github/workflows
laurensandClaude Opus 5 31c836f6ca
ci / android head (push) Successful in 3m46s
ci / desktop nightly (push) Canceled after 0s
ci / api image (push) Canceled after 0s
ci / build and test (push) Canceled after 26m51s
Stop the RPM verification failing on packages that are correct
CI run 161 failed the linux packaging step with

    The package was built and /opt/DodoSSH/DodoSSH is not in it.

and then listed the package contents, which contain /opt/DodoSSH/DodoSSH. The
package was fine. The check was not.

◆ A READER THAT STOPS EARLY, UNDER pipefail.

    if ! printf '%s\n' "$files" | grep -qxF "$expected"; then

grep -q exits on its first match. printf is still writing thousands of paths, so
it dies of SIGPIPE with status 141; pipefail makes 141 the pipeline's status; `!`
inverts it; and a check that found what it was looking for reports the opposite.

The exit code names the second instance of the same mistake. The diagnostic on the
way out is

    printf '%s\n' "$files" | head -40 >&2
    exit 1

and head stops at forty lines, so printf takes SIGPIPE again and `set -e` ends the
script there. Which is why the job exited 141 rather than the 1 the script asked
for, and why the listing in the log stops mid-alphabet.

◆ WHY IT LOOKED LIKE SOMEBODY ELSE'S COMMIT.

It is a threshold, not a constant. The writer only blocks once it has more than a
pipe buffer left to write — about 64 KB on Linux — so for as long as the published
tree was small the whole list fitted, printf finished, and the pipeline returned
grep's own 0. The check has been wrong since it was written and correct in effect
until the path text crossed 64 KB, which is what the commit before this one did.
Reproduced both sides of the threshold locally:

    4,440 bytes  -> pipeline status 0
    90,940 bytes -> pipeline status 141

Every reader in that block now consumes all of its input: `grep pattern
>/dev/null` in place of `grep -q pattern`, same exit status, reads to the end; and
`awk 'NR<=40'` in place of `head -40`, same forty lines, reads to the end. `|| true`
would have silenced the symptom and taken a real failure of the writer with it.

The other three checks in the same block had the same shape with small inputs —
requires and provides are dozens of lines — so they were latent rather than
failing. Fixed anyway, because the next thing to grow is not predictable from here.

Same for the three publish-verification loops in ci.yml, which grep a release's
JSON for each asset name it should carry. Small today; the loops exist because a
run once created a release, uploaded nothing and reported success, so a false
answer from them is the one thing they must not give.

`ensure skia's native dependency` is left alone deliberately. `ldconfig -p | grep
-q` is the same shape over an input that genuinely exceeds a pipe buffer, but that
step sets `-eu` without `pipefail`, so the pipeline's status is grep's and the
SIGPIPE is invisible. Changing it would be churn; the reason it is safe is worth
knowing.

Verified by lifting the patched loop out of the script and running it against a
synthetic 89 KB listing: complete package passes, a package genuinely missing
/opt/DodoSSH/DodoSSH exits 1 with its forty lines of diagnostic intact. The real
proof is the next run of the job.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 15:02:58 +02:00
..