From 728102a3ba76c0db5cac6c3ca224bc39fbd09037 Mon Sep 17 00:00:00 2001 From: cluade-reviewer-andresmgsl Date: Wed, 5 Aug 2026 12:22:20 +0000 Subject: [PATCH] fix(issueflow): issue_payload_valid refuses an empty payload on jq 1.6 too (#198) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `CI / test` was red at 97e63ac on a case that passes on this box: upstream's own "an empty payload is refused". The cause is not the test. `jq -e` disagrees with itself across versions on EMPTY input. jq 1.7 exits 4 — no valid result was ever produced. jq 1.6 exits 0. Measured both ways today against the same filter. This instance's runner image (ghcr.io/catthehacker/ubuntu:act-22.04) carries jq 1.6. So on this forge the guard #247 D3 added specifically to refuse an unreadable read was ACCEPTING one: an empty body read as a valid issue payload, and the sweep would have reconciled an issue from a payload it never received. The test is upstream's, it is correct, and it passes on a GitHub runner — which is why upstream never saw this. The fix does not depend on jq's exit code for an input it never receives: the payload is read, emptiness is decided in the shell, and jq judges only a non-empty body. Verified under BOTH jq versions, not just the one on this box: empty refused and healthy accepted on 1.6 and 1.7, and the whole suite green under jq 1.6 — 28 test files, 0 failed — as well as under 1.7. Refs #198 --- .../issueflow-reconcile/issueflow-reconcile.sh | 15 ++++++++++++++- changelog.d/198.md | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/actions/issueflow-reconcile/issueflow-reconcile.sh b/actions/issueflow-reconcile/issueflow-reconcile.sh index cf7022a..fbe3d16 100644 --- a/actions/issueflow-reconcile/issueflow-reconcile.sh +++ b/actions/issueflow-reconcile/issueflow-reconcile.sh @@ -609,9 +609,22 @@ issue_payload_valid() { # $1 = the requested issue; payload on stdin # one catches an HTTP 200 whose body is `null`, which exits 0 and empties it # just the same. `.number` is checked against the issue asked for, so a # payload about some other issue can never be reconciled as this one. + # THE EMPTINESS CHECK IS NOT REDUNDANT, and it is not stylistic. `jq -e` + # disagrees with itself across versions on empty input: jq 1.7 exits 4 (no + # valid result was ever produced), jq 1.6 exits **0**. This instance's + # runner image (ghcr.io/catthehacker/ubuntu:act-22.04) carries jq 1.6, so + # without this line an EMPTY payload reads as a valid issue payload here — + # the precise thing D3 added this guard to refuse — and the sweep would + # reconcile an issue from a body it never received. Measured both ways, + # 2026-08-05: `jq -e '' /dev/null 2>&1 + ' <<<"$payload" >/dev/null 2>&1 } skipped_tail() { # $1 = skip count, $2 = the issue numbers → the D6 line, or nothing diff --git a/changelog.d/198.md b/changelog.d/198.md index 5a58f55..e9f5f22 100644 --- a/changelog.d/198.md +++ b/changelog.d/198.md @@ -40,6 +40,11 @@ speaks and refuses by name on a runner without it, instead of dying with `command not found` on every sweep. #205 ports it to REST (#198). +- `issue_payload_valid` refuses an empty payload on jq 1.6 as well as 1.7. + `jq -e` exits 4 on empty input under 1.7 and **0** under 1.6, and this + instance's runner carries 1.6 — so the guard #247 D3 added to refuse an + unreadable read was accepting one here (#198). + - The post-merge nudge strips a trailing slash from the server URL, so a forge URL carrying one does not render `//owner/repo` (#198).