Skip to content

fix(scripts): prevent sigpipe exit 141 in post-code commit subject extraction - #2001

Open
jefferyb wants to merge 4 commits into
fullsend-ai:mainfrom
jefferyb:fix/post-code-commit-subject-sigpipe
Open

jefferyb wants to merge 4 commits into
fullsend-ai:mainfrom
jefferyb:fix/post-code-commit-subject-sigpipe

Conversation

@jefferyb

Copy link
Copy Markdown

Summary

Prevent intermittent POSIX SIGPIPE (exit 141) failures in post-code when extracting the first commit's subject line on multi-commit branches under set -eo pipefail.

Problem

In scripts/post-code.src.sh, commit subject extraction was performed using:

first_commit_subject=$(git log "${base_sha}..${head_sha}" --pretty=format:%s | head -1)

Under set -eo pipefail, when head -1 reads the first line and terminates immediately, the pipe is closed. If git log buffers output or writes additional data after the pipe has closed, the OS raises SIGPIPE (signal 13), causing git log to exit with status 141. Under pipefail, this fails the entire pipeline and terminates post-code.sh unexpectedly.

Solution

  1. Replace head -1 with sed -n '1p', which consumes the first line and allows the stream to drain cleanly without prematurely closing the pipe descriptor or triggering SIGPIPE.
  2. Add a regression test in scripts/post-code-test.sh simulating multi-commit output under set -eo pipefail to ensure zero exit code even with pipe buffer saturation.
  3. Rebuild bundled scripts/post-code.sh via make script-build and verify bundle parity (make check-bundle).

Verification

  • Ran scripts/post-code-test.sh — verified git integration and SIGPIPE pipefail regression tests pass cleanly.
  • Ran make check-bundle — verified 0 diff and clean bundle parity.
  • Tested under bash 3.2 (macOS) and bash 5.x.

…traction

When multiple commits are pushed, post-code extracts the first commit
subject using git log | head -1. Under set -eo pipefail, head exits
immediately after line 1, sending SIGPIPE (13) to git log. Depending on
OS buffering and timing, git log may exit with 141, terminating post-code.

Use sed -n '1p' which drains the stream to EOF without premature pipe
closure, ensuring zero exit code under pipefail. Also add a pipefail
regression test in post-code-test.sh.

Signed-off-by: Jeffery Bagirimvano <jefferyb@redhat.com>
@jefferyb
jefferyb requested a review from a team as a code owner November 13, 2026 17:20
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Prevent SIGPIPE during multi-commit PR title selection

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Drain commit history while selecting the first subject, preventing SIGPIPE failures under
 pipefail.
• Add a large-history regression test that verifies successful extraction and preserves
 single-commit coverage.
• Rebuild the bundled script to match the source change.
Diagram

graph TD
  Count{"Multiple commits?"} -->|Yes| History["Reverse git log"] --> First["Drain with sed"] --> Subject["Commit subject"] --> Title["PR title"]
  Count -->|No| Latest["Latest commit"] --> Subject
Loading
High-Level Assessment

Keep the stream-draining sed pipeline: it preserves the existing oldest-commit selection with a minimal change. Resolving the first commit separately would add commands and complexity without a clear benefit.

Files changed (3) +28 / -6

Bug fix (2) +2 / -2
post-code.shMirror the SIGPIPE fix in the bundled script +1/-1

Mirror the SIGPIPE fix in the bundled script

• Replaces 'head -1' with 'sed -n '1p'' in the bundled multi-commit subject pipeline, matching the source script.

scripts/post-code.sh

post-code.src.shDrain multi-commit subject output before selecting the first line +1/-1

Drain multi-commit subject output before selecting the first line

• Uses 'sed -n '1p'' instead of 'head -1' so Git can finish writing its output without a prematurely closed pipe under 'pipefail'. The single-commit path is unchanged.

scripts/post-code.src.sh

Tests (1) +26 / -4
post-code-test.shCover first-subject extraction under pipefail +26/-4

Cover first-subject extraction under pipefail

• Updates the real-Git integration test to use 'sed', then adds 120 padding commits and checks that extraction returns the first subject with exit code zero under 'set -eo pipefail'. Saves the initial feature commit so the single-commit case can still be tested after the larger history is created.

scripts/post-code-test.sh

@qodo-code-review

qodo-code-review Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. New pipefail regression test cannot catch a revert of the fix ✓ Resolved

Resolving commit: d2bc837

Resolution reason
Adds a static grep check over both post-code.src.sh and post-code.sh that fails if COMMIT_SUBJECT
uses head - instead of sed -n '1p', and changes the pipefail test to eval the production
COMMIT_SUBJECT line from POST_SCRIPT rather than an inline re-implementation.
Description
The new 'multi-commit-git-integration-pipefail-safe' block in scripts/post-code-test.sh runs its
own inline git log ... | sed -n '1p' pipeline and never invokes post-code.src.sh or the bundled
post-code.sh. If someone reverts the production line back to head -1, this test still passes
because it only checks the inline sed pipeline.


Informational

2. Test suite gains 120 commits on every run ✓ Resolved

Resolving commit: d2bc837

Resolution reason
Reduced the padding loop from 120 to 12 git commits by using 8KB subjects per commit, keeping total
subject output above 64KB so the SIGPIPE regression check remains meaningful, cutting per-run commit
overhead.
Description
The new loop creates 120 extra commits, each with a roughly 600-character subject, on every run of
post-code-test.sh. Each git commit spawns a process and writes objects, which adds measurable
runtime to the CI test job.

Grey Divider

Context sources
✅ Compliance rules (platform): 55 rules
✅ Skills: 4 invoked
  code-review
  code-implementation
  pr-review
  docs-review
✅ Cross-repo context — repo relationships
Review mode: Auto: 🚀 Fast: Localized shell pipeline fix with focused regression coverage and limited blast radius.

Grey Divider

Tip of the day
💡 Did you know, you can start a comment with 'qodo' or '@qodo' to chat about any finding

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread scripts/post-code-test.sh Resolved
Comment thread scripts/post-code-test.sh Resolved
…KB subjects

Signed-off-by: Jeffery Bagirimvano <jefferyb@redhat.com>
Comment thread scripts/post-code-test.sh Outdated
# shellcheck disable=SC2030,SC2034,SC2153
MERGE_BASE="${_mc_merge_base}"
PATH="$(dirname "${MC_REAL_GIT}"):${PATH}"
eval "${_mc_pipefail_line}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion - should we use eval "${_mc_pipefail_line}" || exit $? here? if the pipeline prints the right subject and then exits 141, the printf below can still make this check pass.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch — thanks @Benkapner! Because the outer || _mc_pipefail_exit=$? suppresses set -e even inside set -eo pipefail command substitutions, a failing eval previously wouldn't exit before printf.

Fixed in 1df3347ad by adding || exit $? after eval "${_mc_pipefail_line}", and verified with shellcheck --severity=warning, make check-bundle, and scripts/post-code-test.sh in both source and bundled modes.

Signed-off-by: Jeffery Bagirimvano <jefferyb@redhat.com>
Comment thread scripts/post-code-test.sh Outdated
${MC_REAL_GIT} -C "${_mc_repo}" commit -q -am "fix(#42): padding commit ${_mc_i} ${_mc_pad}"
done

_mc_pipefail_line="$(grep -m1 -E "COMMIT_SUBJECT=.*sed -n '1p'" "${POST_SCRIPT}")"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM: Reverting the fix aborts the whole test suite instead of reporting FAIL

This file runs under set -euo pipefail (line 10). If the sed -n '1p' pipeline is gone from COMMIT_SUBJECT=, for example after a revert to head -1, this grep -m1 exits 1 and errexit kills the script on this line. The two multi-commit-script-uses-sed FAIL lines print first, but multi-commit-git-integration-pipefail-safe never reports. Every later assertion in the file (single-commit, PR body, gitleaks, signoff and more) is skipped, cleanup does not run, and no summary is printed.

The behaviour test also finds its pipeline by grepping for the sed text, so it never runs a head -1 pipeline. Nothing shows that the >64KB fixture actually reproduces exit 141.

This is separate from the earlier thread on this test, which is fixed. That thread said the test did not run the production line at all.

Suggestion: guard the extraction:

_mc_pipefail_line="$(grep -m1 -E "COMMIT_SUBJECT=.*sed -n '1p'" "${POST_SCRIPT}" || true)"

If the result is empty, print FAIL: multi-commit-git-integration-pipefail-safe (COMMIT_SUBJECT pipeline not found) and increment FAILURES instead of running eval. Optionally, add a control run of the same git log ... | head -1 pipeline and expect exit 141. That shows the fixture really fills the pipe buffer.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8662279 (8662279).

  • Guarded the grep -m1 -E "COMMIT_SUBJECT=.*sed -n '1p'" "${POST_SCRIPT}" || true lookup so a reverted/missing pipeline fails multi-commit-git-integration-pipefail-safe cleanly instead of aborting the test script via errexit.
  • Extracted _eval_commit_subject_pipefail and added a control assertion (multi-commit-git-integration-control-head-sigpipe) replacing sed -n '1p' with head -1 and verifying exit code 141 (SIGPIPE), confirming the >64KB commit fixture reproduces the pipe overflow failure.
  • Verified with shellcheck --severity=warning scripts/post-code-test.sh, make check-bundle, SCRIPT_TEST_TARGET=source bash scripts/post-code-test.sh, and SCRIPT_TEST_TARGET=bundled bash scripts/post-code-test.sh (all passed).

Signed-off-by: Jeffery Bagirimvano <jefferyb@redhat.com>

This branch has not been deployed

No deployments
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.

3 participants