Skip to content

test(config): stop a broken pipe preempting the exit-code diagnosis - #6455

Open
johnstonmatt wants to merge 1 commit into
developfrom
fix/config-release-path-filter-epipe
Open

test(config): stop a broken pipe preempting the exit-code diagnosis#6455
johnstonmatt wants to merge 1 commit into
developfrom
fix/config-release-path-filter-epipe

Conversation

@johnstonmatt

Copy link
Copy Markdown
Contributor

Summary

filterCommitsToPackage feeds commit hashes to git diff-tree --stdin over the subprocess's stdin. A git that rejects its arguments — a cwd outside any repository, say — exits before it reads a single hash, so the write that follows can land on a process that has already gone and raise EPIPE: broken pipe, send.

Which error surfaces is a race against process startup: green on an idle machine, red on a loaded CI runner. The exit code and stderr below the write are the real diagnosis, so a broken pipe on stdin is now dropped and the reporting left to them. Any other write failure still throws.

isBrokenPipe matches on the EPIPE code rather than the message text, since Node and Bun word it differently.

Context

Split out of the workers stack. This landed on FUNC-853/workers-logs-command (#6410) to stabilise that branch's CI, but it has nothing to do with workers — it is a packages/config release-script fix, and it should not merge or revert with the workers work. Raised in review on #6410.

Carries one fix on top of the original commit: isBrokenPipe had been inserted between filterCommitsToPackage's JSDoc and the function itself, orphaning the doc. The helper now sits above it.

`git diff-tree --stdin` given a cwd outside any repository exits before it
reads a hash, so the write that follows can land on a dead process and raise
`EPIPE: broken pipe, send` instead of the exit-code error the caller reports.
Which one surfaces is a race against process startup — green on an idle
machine, red on a loaded CI runner.

The exit code and stderr are the diagnosis, so a broken pipe on stdin is
dropped and the reporting left to them.
@johnstonmatt
johnstonmatt requested a review from a team as a code owner September 3, 2026 22:38
johnstonmatt added a commit that referenced this pull request Sep 3, 2026
…gnosis"

This reverts b772491.

The fix is sound but has nothing to do with workers logs; it landed here to
stabilise this branch's CI. Moved to #6455 off develop so it does not merge or
revert with the workers work. Raised in review on #6410.

Until #6455 lands, the `packages/config` release-script test it stabilises can
flake on a loaded runner.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 AI Review

Both reviews completed: Claude reported five findings and Codex reported none. One pre-existing sibling EPIPE-handling gap is confirmed, one hypothetical EPIPE-plus-zero-exit completeness risk remains uncertain, and three findings are refuted. No confirmed defect was found in the PR's changed behavior itself.

Findings

Severity Location Category Sources Claim
🟡 MINOR packages/config/scripts/semantic-release-path-filter.ts:133 error-handling claude A caught EPIPE followed by a zero git exit code could allow parsing incomplete stdout without detecting truncated input.
🟡 MINOR packages/config/scripts/build.ts:74 error-handling claude renderJsonSchema has the same unguarded subprocess-stdin write pattern, so an early oxfmt exit can surface a broken-pipe error before its exit-code and stderr diagnosis.

Findings outside the diff

  • 🟡 MINOR packages/config/scripts/build.ts:74 — renderJsonSchema has the same unguarded subprocess-stdin write pattern, so an early oxfmt exit can surface a broken-pipe error before its exit-code and stderr diagnosis.
Refuted findings (kept for transparency, not posted as review comments)
  • packages/config/scripts/semantic-release-path-filter.ts:132 (resource-cleanup): The catch branches leave the subprocess and stream-reader promises uncleaned, potentially leaking resources or causing unhandled rejections.
    Refuted: A recognized EPIPE continues to line 139, which awaits proc.exited, stdoutText, and stderrText; the reader has already closed the pipe, so skipping stdin.end does not leave git waiting for EOF. The non-EPIPE rethrow behavior already existed before this PR, and the code provides no evidence that either reader rejects unhandled.
  • packages/config/scripts/semantic-release-path-filter.ts:59 (test-coverage): The private isBrokenPipe predicate lacks a direct unit test, so a runtime error-shape change could restore the flaky failure without test detection.
    Refuted: The integration test exercises the relevant runtime boundary and fails if a write error escapes instead of producing the expected git diagnosis. A unit test using fabricated objects would only test the predicate's comparison and would not validate Bun's actual error shape.
  • packages/config/scripts/semantic-release-path-filter.ts:56 (documentation): Mentioning Node's EPIPE convention is misleading because the current caller uses Bun.spawn.
    Refuted: The comment does not claim this call executes under Node; it accurately explains why the stable code property is checked instead of runtime-specific message text. The Bun-only caller does not make that comparison incorrect.

Stats

Claude findings: 5 · Codex findings: 0 · Confirmed: 1 · Refuted: 3 · Uncertain: 1


Models: claude-opus-5 + gpt-5.6-sol · Trigger: auto · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

try {
await proc.stdin.write(`${hashes.join("\n")}\n`);
await proc.stdin.end();
} catch (cause) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 MINOR · error-handling · source: claude

A caught EPIPE followed by a zero git exit code could allow parsing incomplete stdout without detecting truncated input.

Evidence: packages/config/scripts/semantic-release-path-filter.ts:133-137 suppresses EPIPE, while lines 139-159 reject only nonzero exits and otherwise parse and return the observed hashes.

Suggested fix: Track whether the write failed and reject a zero-exit result unless completeness can otherwise be established.

Adjudication (uncertain): The control flow permits the claimed combination, but the harmful outcome requires git diff-tree to close stdin and exit successfully before consuming all hashes. Neither the implementation nor tests establish that this can occur, so silent truncation could not be verified.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@3bb7b37df0362f9e9e831b6e1049be5d3cdb22d4

Preview package for commit 3bb7b37.

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