Skip to content

fix: keep bounded PG harness failure diagnostics - #1750

Merged
bcdonadio merged 4 commits into
mainfrom
fix/1622-s21-harness
Oct 25, 2026
Merged

bcdonadio merged 4 commits into
mainfrom
fix/1622-s21-harness

Conversation

@bcdonadio

Copy link
Copy Markdown
Contributor

Why

When a PostgreSQL harness run failed with more than 64 KiB of output (MAX_CAPTURED_OUTPUT_BYTES), the harness threw away the whole diagnostic and printed only PostgreSQL harness diagnostic exceeded the safe capture limit. This happened at two points. The 64 KiB ring of the vitest child overflowed, and the bounded raw tail was discarded because it could not be sanitized safely. The final diagnostic was all-or-nothing. A large failing suite such as surface parity therefore never showed the failing test or assertion. This hid the causes of #1599, #1619, #1647 and #1718.

Closes #1622

How

All changes are in scripts/postgresql-harness.mjs:

  • Final diagnostic: sanitizedHarnessErrorDetails sanitizes the full text first. If the result is over the limit, it keeps a marker with the byte count, a head, an elision line and a tail, all within the limit and cut on UTF-8 code point boundaries.
  • Redaction before the ring: a stream redactor sanitizes child output line by line before it enters the 64 KiB ring, so a truncated tail never contains raw text. It covers configured secrets, postgresql:// URLs and PEM blocks, using the same marker grammar as sanitizeHarnessText.
    • Markers are scanned in order with nesting depth.
    • A block still open at end of stream is dropped.
    • Overlong lines are dropped with a marker. The redactor keeps PEM state across them: a BEGIN keyword opens a block (fail closed) and only a confirmed END closes it. Markers split across chunks are handled.
  • Truncation still fails the run: an overflowed or dropped-line stream rejects, even for an exit-0 child, whatever the chunking. The thrown error carries a labelled, bounded, sanitized stdout and stderr tail on error.stderr, which the final diagnostic reads. It is never returned as successful output.
  • Fail-closed cases kept: if a configured secret contains a newline, the redactor is disabled and raw truncated output is omitted, as before.
  • Ring start: a truncated ring starts on a code point boundary.

Previously discarded tail content now surfaces after redaction.

Testing

  • test/scripts/postgresql-harness.test.ts: 167/167. The new tests go through runProcess/runSanitizedProcess with fake children. They cover:
    • secrets placed on each excerpt cut;
    • multibyte characters at every cut and at the ring start, with real ring overflow;
    • secrets and URLs split across chunks;
    • repeated, nested and unterminated PEM blocks;
    • END followed by BEGIN on one line;
    • incomplete END prefixes;
    • blocks opened or closed on overlong lines;
    • labels of 64, 70 and 65+ characters, split at every position;
    • exit-0 children whose output was discarded, under four chunk partitions;
    • container logs appended after the child excerpt.
  • eslint and tsc --noEmit produced no output.
  • The branch includes a signed merge of main.

Reviewer guide

Start with createStreamRedactor (scanPemMarkers for complete lines, scanDropped for overlong text), then runProcess's truncation flags, capturedOutputFailure, and boundedDiagnosticExcerpt. The tests are grouped near the end of the harness test file.

The PostgreSQL harness replaced a failure diagnostic larger than
MAX_CAPTURED_OUTPUT_BYTES with one fixed line, and a child stream that
overflowed its 64 KiB ring was discarded with a bare error. A large
failing suite therefore lost the failing test name and assertion.

The final diagnostic is now sanitized in full first, then bounded to a
head and tail excerpt with a marker holding the original byte count. Cuts
fall on UTF-8 code point boundaries and the result stays within the limit.

Child output is redacted before it enters the ring, never afterwards: a
truncated raw tail may begin inside a secret or PEM block, and redaction
state cannot be recovered from it. createStreamRedactor redacts per
complete line (exact secrets, postgresql URLs, PEM BEGIN through END,
including blocks still open at end of stream); the trailing partial line
is held in a bounded buffer and an overlong line is dropped with a marker.

When a redacted stream still overflowed, the run still fails, but the
thrown error carries the bounded sanitized stdout and stderr tails in
stderr, because harnessErrorDetails reads stderr only. The same applies to
the expanded sanitized output branch. Container logs are redacted the same
way. Raw truncated output (a secret containing a newline disables the
redactor) is still omitted, fail closed.

Previously discarded tail content now surfaces after redaction. Scripts
only, so no changeset.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Round 1 review of the harness diagnostics found secret leaks and an
acceptance gap in the line-wise redactor.

PEM state now comes from one ordered scanner that walks complete BEGIN
and END markers left to right, seeded with the current block depth, for
normal lines and for dropped text alike. A block opened right after an
END, a BEGIN nested before the first END, an END prefix that is not a
complete marker, and an END on an overlong line inside an open block are
all handled, and state is committed in both directions. Dropped text keeps
a 79 character carry so a marker split across chunks is still recognised;
labels over 64 characters are not markers.

The line bound now applies to every complete line, and a dropped line
counts as capture truncation, so an exit-0 child whose output was
discarded rejects like a ring overflow regardless of chunk boundaries.
The ring start also advances to a UTF-8 code point boundary.

A BEGIN with no END stays open to the end of the stream, which fails
closed.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Round 2 review found that the stream redactor accepted PEM labels of at
most 64 characters, while sanitizeHarnessText accepts any non-empty
hyphen-free label. A block with a longer label therefore surfaced its body
once the ring had dropped the BEGIN line, where the full-text pass could
no longer repair it.

Complete lines now use the sanitizer's marker grammar. Dropped text is
scanned by a streaming marker scanner that keeps only a keyword-prefix
carry and the marker state, so a label of any length can span writes. A
BEGIN keyword opens a block at once, confirmed or not, and only a
confirmed END marker closes one; a hyphen inside a label never completes
a marker.

The UTF-8 ring test now overflows the ring with several lines under the
line cap, so it exercises the code point cut. The old long-label test that
asserted ordinary text is replaced by public-path tests.

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
@bcdonadio bcdonadio self-assigned this Oct 25, 2026
@bcdonadio
bcdonadio enabled auto-merge October 25, 2026 05:43
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T05:44:35.703544Z dfbedd2 PR opened
🔒 Security Review ✅ Completed 2026-10-25T05:46:25.403771Z dfbedd2 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfbedd210c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/postgresql-harness.mjs
@bcdonadio
bcdonadio merged commit 59dae18 into main Oct 25, 2026
25 checks passed
@bcdonadio
bcdonadio deleted the fix/1622-s21-harness branch October 25, 2026 06:15
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.

PG harness hides failure output past capture limit

1 participant