Skip to content

Sanitize NUL bytes in operation and effect details before jsonb insert - #216

Open
tamirms wants to merge 5 commits into
mainfrom
harden-ingest-details-jsonb
Open

Sanitize NUL bytes in operation and effect details before jsonb insert#216
tamirms wants to merge 5 commits into
mainfrom
harden-ingest-details-jsonb

Conversation

@tamirms

@tamirms tamirms commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What

Strings derived from ledger data are not guaranteed to be representable in a Postgres jsonb column. This makes the operation and effect details writes robust to such values by removing any NUL character — which jsonb cannot store — before the insert.

How

  • Adds a small helper that removes NUL characters from a marshaled details document by decoding it, stripping NUL from its string values, and re-encoding, so JSON parsing and escaping are handled by encoding/json rather than by editing serialized bytes. The common (no-NUL) case is returned untouched.
  • Applies it in the operation and effect batch insert builders — the only two writers of the history_operations.details and history_effects.details columns.

Tests

  • Unit tests for the helper, including values that contain the literal escape text and a mix of both.
  • DB-backed regression tests that insert such a details document through both builders and confirm it stores correctly.

Strings derived from ledger data are not guaranteed to be representable in
a Postgres jsonb column. Strip any NUL from the marshaled operation and
effect details at the insert boundary so the write cannot fail on such
values. Includes a unit test and DB-backed regression tests for both the
history_operations and history_effects details columns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings August 5, 2026 08:50
@tamirms
tamirms requested a review from a team August 5, 2026 08:53

Copilot AI 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.

Pull request overview

Sanitizes NUL bytes before storing operation and effect details in PostgreSQL jsonb.

Changes:

  • Adds a JSONB details sanitizer.
  • Applies sanitization to operation and effect batch inserts.
  • Adds unit and database-backed regression tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
operation_batch_insert_builder.go Sanitizes operation details.
effect_batch_insert_builder.go Sanitizes effect details.
details.go Implements NUL escape removal.
details_test.go Tests sanitizer and database writes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/db2/history/details.go
Comment thread internal/db2/history/details_test.go Outdated
tamirms and others added 4 commits August 5, 2026 11:00
Address review feedback:
- sanitizeJSONBDetails could match the six escape bytes when they appear
  as the tail of an escaped backslash, truncating an otherwise-valid
  document into invalid JSON. Walk the marshaled bytes and drop only
  escapes introduced by an unescaped backslash. Adds regression cases.
- Use Require for query prerequisites before indexing the effects slice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the hand-rolled escape scan with a decode / strip-NUL / re-encode
round trip, so JSON parsing and escaping are handled by encoding/json
rather than by editing serialized bytes. UseNumber preserves numeric
precision across the round trip. The no-NUL fast path is unchanged, so
the common ingestion case pays nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The shadow vet in CI's check job flagged an err declaration in an inner
Unmarshal block shadowing the function-scope err from a Marshal call.
Use a small mustMarshal helper so each Unmarshal keeps its own scoped
err with nothing to shadow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The two DB-backed regression tests each provisioned their own database
fixture, adding load to the history package which already runs close to
the 10m per-package race timeout on the slower CI runners. Merge them
into a single test that exercises both jsonb detail columns under one
fixture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

2 participants