Skip to content

feat(agent-bff): reject nested relation field paths in top-level list and count#1736

Open
nbouliol wants to merge 1 commit into
mainfrom
feature/prd-669-reject-nested-relation-field-paths-in-top-level-list-and
Open

feat(agent-bff): reject nested relation field paths in top-level list and count#1736
nbouliol wants to merge 1 commit into
mainfrom
feature/prd-669-reject-nested-relation-field-paths-in-top-level-list-and

Conversation

@nbouliol

@nbouliol nbouliol commented Jul 3, 2026

Copy link
Copy Markdown
Member

What

Adds a pure, syntactic guard in agent-bff that rejects any top-level list/count field path carrying the relation separator : (e.g. company:name) with 422 relation_field_not_supported.

Why

The agent has an authority gap: a top-level list checks browse/scope on the top collection only (packages/agent/src/routes/access/list.ts), whereas listRelated browse-checks the foreign collection (list-related.ts). A relation-target field can thus be projected without the target collection browse/scope check. The BFF must not propagate that gap, so v1 rejects nested relation paths on top-level list/count outright.

Scope

  • relationFieldNotSupported(fields) factory on the existing BffHttpError contract — envelope { error: { type, status, message, details: { fields } } }, details.fields always an array.
  • assertNoRelationFieldPaths(paths) — throwing guard; offending paths deduped, first-seen order; direct-only and empty input pass through. Syntactic only (no schema/allow-list consulted).
  • Guard is internal (imported by path); not exported from the public index.ts.

Non-goals

  • Wiring into live list/count handlers (data-endpoints slice / PRD-639).
  • listRelated/countRelated, allow-list validation, capabilities validation.

Tests

10 focused unit tests: nested path in projection/filter/sort (list) and filter (count); multiple offending; single-as-array; dedupe + order; direct-field & empty pass-through; one toErrorBody wire-envelope assertion. Full agent-bff suite green (374/374), lint clean.

Fixes PRD-669

🤖 Generated with Claude Code

Note

Reject nested relation field paths in top-level list and count requests

  • Adds assertNoRelationFieldPaths that scans field paths for : (relation separator) and throws a 422 error listing the offending paths if any are found.
  • Adds a relationFieldNotSupported error factory producing a BffHttpError with status 422, type relation_field_not_supported, and the offending fields in details.fields.
  • Behavioral Change: top-level list and count requests that include nested relation field paths now return 422 instead of being processed.

Macroscope summarized 843b80c.

… and count

Add a pure syntactic guard that rejects any top-level field path carrying
the relation separator ":" with 422 relation_field_not_supported. Closes an
agent authority gap where a relation-target field could be projected without
the target collection browse/scope check. Guard + tests only; wiring into
live list/count handlers belongs to the data-endpoints slice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GqCtMftj4gwCo2AwicMNL
@linear-code

linear-code Bot commented Jul 3, 2026

Copy link
Copy Markdown

PRD-669

@qltysh

qltysh Bot commented Jul 3, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (2)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/agent-bff/src/http/bff-http-error.ts100.0%
New Coverage rating: A
packages/agent-bff/src/validation/relation-field-guard.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

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