Skip to content

validate.sh: fix flaky fortunes checks (SIGPIPE under pipefail) - #1564

Merged
MDA2AV merged 1 commit into
mainfrom
validate-grep-herestring
Oct 14, 2026
Merged

MDA2AV merged 1 commit into
mainfrom
validate-grep-herestring

Conversation

@MDA2AV

@MDA2AV MDA2AV commented Oct 14, 2026

Copy link
Copy Markdown
Owner

Summary

The fortunes checks can fail on a correct page. validate.sh runs under set -o pipefail, and the checks were written as echo "$body" | grep -q PATTERN. When grep finds an early match it exits while echo is still writing the rest of the ~25 KB page. echo dies of SIGPIPE (PIPESTATUS=(141 0)), so the pipeline reports failure even though grep matched.

This is what failed #1548 locally once its directory name was fixed: FAIL [GET /fortunes XSS escape]: <script> in row 11 not properly HTML-escaped, although row 11 comes back as &lt;script&gt;alert(&quot;….

Measured by running the three checks 2000 times on the same saved, correct page:

check echo | grep -q (two runs) here-string
XSS escape 769, 1076 0
<!DOCTYPE html> 116, 173 0
runtime-injected row 1, 1 0

The fix matches captured variables with here-strings (grep -q PATTERN <<< "$var"), so no writer process can be killed. The other four places that pipe a captured variable into grep -q (TLS resumption probe, close_notify probe, json-tls Content-Type check) are switched too, so the rule is the same everywhere. Those four look at small strings and probably never raced. Pipelines that feed a live command into grep -q are left alone: the one whose output is big enough to matter (openssl s_client -help) showed 0 failures in 600 runs, because openssl writes its help text in a single call.

For context, FAIL [GET /fortunes XSS escape] also shows up in recent failed CI runs for Ktor (35351621895), vanilla-epoll (38080909170) and morojs (38093469575). I haven't checked whether those were this race.

Test plan

  • bash -n scripts/validate.sh
  • 2000-iteration loop of the old vs new checks on a saved /fortunes page (table above)
  • Negative control: the new checks still fail 5/5 on an unescaped <script>alert(1)</script> page
  • Full scripts/validate.sh aspnet-minimal-satorigc (Add aspnet-minimal-satoriGC #1548's entry, fixed) with this change: 116 passed, 0 failed

🤖 Generated with Claude Code

… grep -q

Under `set -o pipefail`, `echo "$body" | grep -q PATTERN` fails whenever
grep finds an early match and exits while echo is still writing: echo
dies of SIGPIPE (exit 141) and the pipeline reports failure although grep
matched. The fortunes checks hit this on a correct ~25 KB page, 769 of
2000 runs on the XSS check and 116 on the DOCTYPE check, and it showed up
on #1548 as a false "<script> in row 11 not properly HTML-escaped". A
here-string has no writer to kill: 0 of 2000.

The other four places that pipe a captured variable into grep -q (the TLS
resumption and close_notify probes, the json-tls Content-Type check) are
switched too, so the rule is the same everywhere.
@MDA2AV
MDA2AV merged commit 0bf9473 into main Oct 14, 2026
25 of 182 checks passed
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