Skip to content

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

Merged
nbouliol merged 1 commit into
mainfrom
feature/prd-669-reject-nested-relation-field-paths-in-top-level-list-and
Jul 7, 2026
Merged

feat(agent-bff): reject nested relation field paths in top-level list and count#1736
nbouliol merged 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.

@nbouliol

nbouliol commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Code review — commit 843b80c

Reviewed on two axes (repo standards + PRD-669 spec). Verdict: clean, mergeable.

Standards

No hard violations.

  • Inline 422 / relation_field_not_supported in bff-http-error.ts are magic values, but consistent with the existing factory pattern in that file (400, 'invalid_timezone', etc.) — fine as-is.
  • Low-priority judgement calls: O(n²) dedup via !offending.includes(path) in the loop (a Set would be linear, though input cardinality is tiny); captureError helper used by only 3 of the tests while the rest use toThrow (mild dual-style, but the toEqual-on-details cases legitimately need it).
  • Tests are strong: name = assertion, one behavior each, edge cases covered (empty/single/multiple/dedup/passthrough), exact wire-envelope assertion.

Spec (PRD-669)

  • All 5 acceptance criteria implemented and tested. Single path-list primitive is explicitly permitted by the spec.
  • details.fields always an array incl. single-path case ✓. Syntactic-only (no schema/allow-list) ✓.
  • Dedup + first-seen ordering is not named in the spec but is a defensible reading of AC4 and is tested.
  • Guard being uncalled by any route is expected — wiring is a non-goal (Slice 3 / PRD-639).

No blocking issues.

🤖 Generated with Claude Code

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

LGTM

@nbouliol nbouliol merged commit 92bb366 into main Jul 7, 2026
32 checks passed
@nbouliol nbouliol deleted the feature/prd-669-reject-nested-relation-field-paths-in-top-level-list-and branch July 7, 2026 14:10
forest-bot added a commit that referenced this pull request Jul 7, 2026
# @forestadmin/agent-bff [1.5.0](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/agent-bff@1.4.1...@forestadmin/agent-bff@1.5.0) (2026-07-07)

### Features

* **agent-bff:** reject nested relation field paths in top-level list and count ([#1736](#1736)) ([92bb366](92bb366))
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