Skip to content

buzz-search: read profile names without the profile_name_fields function - #9397

Merged
TheSentinel454 merged 2 commits into
mainfrom
elrond/profile-name-fields-inline
Nov 13, 2026
Merged

TheSentinel454 merged 2 commits into
mainfrom
elrond/profile-name-fields-inline

Conversation

@TheSentinel454

@TheSentinel454 TheSentinel454 commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

What

This is phase 1 of 2 for retiring the plpgsql function profile_name_fields(text). Its only caller, profile name search (search_profile_names), now gets name and display_name from an inline SQL expression (PROFILE_NAME_FIELDS in crates/buzz-search/src/query.rs) instead.

The function's exception handler made unreadable kind:0 content have no names rather than fail the search. The inline version keeps that guarantee in two steps:

  • pg_input_is_valid(content, 'jsonb') rejects the soft parse errors: a \^@ escape, a lone surrogate, a huge number, and malformed JSON.
  • A bracket bound for deep nesting. PostgreSQL's JSON parser is recursive. Past about 10k levels at the default max_stack_depth, it raises stack depth limit exceeded, and pg_input_is_valid does not catch that. I confirmed this on PG 17: depth 10k is fine and 20k raises. So content with more than 4096 [ and { is never parsed and has no names. The count bounds the depth. Ingest already rejects kind:0 content nested deeper than 128 levels (serde_json), so this only matters for content stored another way.

OFFSET 0 keeps the parse from being copied into each reference to doc, so each candidate row is parsed once, plus one validity pass. The plpgsql function also parsed each row once.

Behavior change (edge only): a kind:0 with more than 4096 brackets, even inside strings, is no longer findable by name. Real profiles don't come close, and a picture data URL is base64 with no brackets.

pg_input_is_valid needs PostgreSQL 16 or later. CI runs 16, and the dev compose runs 17.

Phase 2 (not here): a migration and desired-state change drops the function, its schema/functions/ file and its schema.sql entry once this release has shipped.

Tests

  • profile_names_survive_unparsable_content already stores a \^@ profile, a lone-surrogate profile, a 1e1000000 profile and a 60k-deep profile next to a plain one, and requires the search to return only the plain one. It now also covers the bound itself: a profile with exactly 4096 brackets, all but one inside a string, is still found.
  • Must-fail mutants, each run on Blox: bracket bound removed (the search fails with a stack overflow), validity check removed, bound tightened by one, and the string-type check loosened.

What got simpler

Profile search no longer depends on a database function. Name extraction lives next to the rest of the search SQL it feeds.

Verification

Blox, at be0db303ea90033cc2c37ac8f8f07c27f4b08e31 (clean tree):

Gate Result
cargo fmt --all --check pass
cargo clippy -p buzz-search --all-targets -- -D warnings pass
cargo nextest run -p buzz-search --lib 4/4
scripts/postgres-test-run.sh -p buzz-search --tests -E 'test(/profile_names/)' 4/4
Must-fail mutants (no bound, no validity check, bound tightened by one, non-string names allowed) 4/4 killed

Probe on PostgreSQL 17.11: pg_input_is_valid returns false for \^@, a lone surrogate, 1e1000000 and truncated JSON; nesting depth 10k is valid; depth 20k raises stack depth limit exceeded. CI runs the full Postgres lanes.

🤖 Generated with Claude Code

buzz-review-completed

Profile name search now extracts `name` and `display_name` from kind:0
content with an inline SQL expression instead of calling the plpgsql
function `profile_name_fields(text)`. Content PostgreSQL cannot read as
jsonb still has no names rather than failing the query: `pg_input_is_valid`
screens out what the function's exception handler caught, except nesting
deep enough to overflow the parser's stack, which it cannot catch. Content
with more than 4096 `[` and `{` is therefore never parsed. Ingest already
rejects kind:0 nested deeper than 128 levels, so only content stored some
other way is affected.

The function stays in the schema; a later migration drops it once this
release has shipped.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Luke Tornquist <[email protected]>
@TheSentinel454
TheSentinel454 marked this pull request as ready for review November 12, 2026 15:39
@TheSentinel454
TheSentinel454 requested a review from a team as a code owner November 12, 2026 15:39
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated, security-focused review generated by Codex.
Use it as a supplement to human review; false positives are possible.

Scope

  • Exact PR diff: cb69ad9e4f21b25954d76f4ce1b406f882dafecc...b5f40f4249ba3098c79dbce18fdd2b0a98117d94
  • Model: gpt-6.1-sol

💡 Click "edited" above to see earlier reviews for this PR.


Review Summary

Overall Risk: NONE

No concrete security, correctness, or reliability regressions identified in the authorized PR range. Community scoping and caller authorization remain intact.

Findings

No concrete security, correctness, or reliability findings were identified.

Notes

  • Review used read-only source and history inspection. Builds and tests were not executed, as requested.

Generated by Codex Security Review |
Requested by: @TheSentinel454 |
Workflow run

@wpfleger96 wpfleger96 left a comment

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.

🤖 No blocking findings. Two independent reviews of this commit (a source trace and a run against real Postgres) agree.

  • Same results as profile_name_fields. I ran the new SQL on a throwaway Postgres 16 container against a valid object; a top-level array, string, number and null; non-string names; \u0000; a lone surrogate; 1e1000000; truncated JSON; empty and NULL content; nesting 4095 deep (just under the bound) and 20k deep (over it); and duplicate keys. Only the objects returned names, and nothing raised. The function's object check carries over because -> returns NULL on a non-object.
  • Search query unchanged otherwise. The community, kind, deletion and channel-less filters, the matching, the per-person ranking, the paging and the verified-profile branch all behave as before.
  • PostgreSQL 16 floor. IS JSON OBJECT in buzz-db already needs 16, so pg_input_is_valid doesn't raise the minimum.
  • Ingest claim holds. kind:0 content goes through serde_json::from_str at ingest, which stops at 128 levels of nesting by default.
  • Retirement order. Keeping the function until a later release follows the deploy-before-contract rule in docs/database.md.
  • CI. The PostgreSQL 16 lane passed, including all four profile-name tests. The red Security check is the hickory-net advisory, and this PR doesn't change the lockfile.

One nonblocking note is inline.

Comment thread crates/buzz-search/src/query.rs Resolved
The 4096-bracket bound in PROFILE_NAME_FIELDS keeps the jsonb parse
inside PostgreSQL's default 2 MB max_stack_depth. Say so in the doc
comment: at a much lower setting, deeply nested content stored outside
ingest can still fail the search. Comment only; no behavior change.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Luke Tornquist <[email protected]>
@github-actions github-actions Bot removed the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 12, 2026
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 12, 2026

@kazemek21 kazemek21 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.

Kyle reviewed this PR and the Nexus review-tracker notes and approved with no comments.

Posted by Codex (gpt-6.1-sol) on behalf of kylez.

@TheSentinel454
TheSentinel454 merged commit 279a31d into main Nov 13, 2026
90 checks passed
@TheSentinel454
TheSentinel454 deleted the elrond/profile-name-fields-inline branch November 13, 2026 00:35
bostonaholic added a commit that referenced this pull request Nov 13, 2026
Co-authored-by: mboston.Engineer <932d3b6ebea6cc83e091551ae46d1c7e7f8f7d0fa8e9cef5e6facc8544af413b@buzz.block.builderlab.xyz>

* origin/main:
  fix(mobile): require Builderlab consent for existing identities (#8823)
  feat(mobile): use HTTP/2 on iOS through app-wide URLSessions (#8897)
  fix(relay): publish a git push only when refs changed; check the protocol by refinement (#9425)
  fix(mobile): show shared chats under Solo (#9348)
  chore(release): release Buzz Desktop version 0.5.29 (#9456)
  feat(mobile): render messages with gpt_markdown 1.3.4 plusparse (#8945)
  fix(acp): bound observer retention by bytes (#7987) (#9436)
  Tune release codegen for faster/smaller binaries (#9434)
  feat(desktop): add dismissible banner pointing to the new buzz app (#9379)
  fix(mobile): keep publishing presence while the app is open (#9441)
  feat(mobile): share into Buzz from the iOS share sheet (#9433)
  fix(mobile): qualify every namesake mention and keep authored mention casing (#9325)
  fix(mobile): match browser GIF timing in the iOS reaction sheet (#9437)
  fix(mobile): play short-delay animation frames at browser speed (#9432)
  buzz-search: read profile names without the profile_name_fields function (#9397)
  buzz-db: build the community deletion lock key in Rust (#9396)
  fix(cli): pair for the active community, skip stopped desktops, accept a bare relay host (#9417)
  test(mobile): run push tests without a gateway dart-define (#9423)
  fix(mobile): never pop Home when archiving from channel settings (#9387)
  perf(acp): reduce observer CPU and lock overhead (#9381)

Signed-off-by: Matthew Boston <[email protected]>
bostonaholic added a commit that referenced this pull request Nov 13, 2026
…count-backfill

Co-authored-by: mboston.Engineer <932d3b6ebea6cc83e091551ae46d1c7e7f8f7d0fa8e9cef5e6facc8544af413b@buzz.block.builderlab.xyz>

* bostonaholic--agent-reply-count:
  fix(mobile): require Builderlab consent for existing identities (#8823)
  feat(mobile): use HTTP/2 on iOS through app-wide URLSessions (#8897)
  fix(relay): publish a git push only when refs changed; check the protocol by refinement (#9425)
  fix(mobile): show shared chats under Solo (#9348)
  chore(release): release Buzz Desktop version 0.5.29 (#9456)
  feat(mobile): render messages with gpt_markdown 1.3.4 plusparse (#8945)
  fix(acp): bound observer retention by bytes (#7987) (#9436)
  Tune release codegen for faster/smaller binaries (#9434)
  feat(desktop): add dismissible banner pointing to the new buzz app (#9379)
  fix(mobile): keep publishing presence while the app is open (#9441)
  feat(mobile): share into Buzz from the iOS share sheet (#9433)
  fix(mobile): qualify every namesake mention and keep authored mention casing (#9325)
  fix(mobile): match browser GIF timing in the iOS reaction sheet (#9437)
  fix(mobile): play short-delay animation frames at browser speed (#9432)
  buzz-search: read profile names without the profile_name_fields function (#9397)
  buzz-db: build the community deletion lock key in Rust (#9396)
  fix(cli): pair for the active community, skip stopped desktops, accept a bare relay host (#9417)
  test(mobile): run push tests without a gateway dart-define (#9423)
  fix(mobile): never pop Home when archiving from channel settings (#9387)
  perf(acp): reduce observer CPU and lock overhead (#9381)

Signed-off-by: Matthew Boston <[email protected]>

This branch was successfully deployed

1 active deployment
codex-review — b5f40f42 Deployed Nov 12, 2026 by TheSentinel454 via Run Codex Security Review #14645
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex-security-review-current The posted Codex security review matches its recorded range.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants