fix: address PR #813 review round 4 (log leak, cross-user chunk ctx, algo, overlap)
1. Don't log unverified result titles: both search algorithms logged top-5 titles at DEBUG before verify-on-read; with owner-level share expansion the unverified set can contain other users' docs. Algorithms now log a count only; the verifying callers (server/semantic, viz_routes, api/visualization) log verified titles after verify-on-read. 2. Cross-user FILE chunk context: get_chunk_with_context + the Qdrant chunk helpers now take accessible_owners and use build_ownership_filter. For files the expanded scope is honoured only after a per-file file_accessible_by_id check (accessible_owners is owner-level, so the gate prevents a one-file share recipient from reading any of the owner's cached chunks). note/deck/ news stay self-only (per-user APIs) — a documented gap. Both chunk endpoints pass accessible_owners. 3. Algorithm usage: SemanticSearchAlgorithm is not dead (it backs the dense-only option on the viz/API surfaces); added a clarifying comment in server/ semantic.py. Additionally wired accessible_owners + verify-on-read into the /api/v1 search routes (unified_search, vector_search) so the astrolabe surface is ACL-aware too — degrading gracefully to self-only/unverified for non-provisioned callers instead of 401. 4. Overlapping conditions: build_ownership_filter no longer lists self in the owner_id MatchAny branch (self is already covered by the user_id branch); the owner_id branch carries only the OTHER owners. Tests: build_ownership_filter dedup + chunk-bbox filter-shape updates; new ACL-aware get_indexed_doc_types, cached-chunk lookup, and end-to-end cross-user file chunk-context (recipient gets the chunk, non-recipient denied) tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ac041d5c97
commit
8deb48e6fa
@@ -129,7 +129,12 @@ def configure_semantic_tools(mcp: FastMCP):
|
||||
accessible_owners = await list_accessible_owners(client.sharing, username)
|
||||
|
||||
try:
|
||||
# Create BM25 hybrid search algorithm with specified fusion
|
||||
# The nc_semantic_search tool deliberately uses BM25-hybrid (dense +
|
||||
# sparse with RRF/DBSF fusion) as the single tool-layer algorithm.
|
||||
# SemanticSearchAlgorithm is not dead code — it backs the dense-only
|
||||
# option that the visualization/API surfaces expose explicitly
|
||||
# (auth/viz_routes.py and api/visualization.py). Both algorithms take
|
||||
# accessible_owners, so ACL-aware search works on every surface.
|
||||
search_algo = BM25HybridSearchAlgorithm(
|
||||
score_threshold=score_threshold, fusion=fusion
|
||||
)
|
||||
@@ -230,6 +235,17 @@ def configure_semantic_tools(mcp: FastMCP):
|
||||
verified_chunk_count,
|
||||
dropped_count,
|
||||
)
|
||||
# Safe to log titles now: these results passed verify-on-read, so the
|
||||
# caller is confirmed to have access (unverified titles were never
|
||||
# logged — see the search algorithms).
|
||||
if verified_results:
|
||||
logger.debug(
|
||||
"Top verified results: %s",
|
||||
", ".join(
|
||||
f"{r.doc_type}_{r.id} (score={r.score:.3f}, title='{r.title}')"
|
||||
for r in verified_results[:5]
|
||||
),
|
||||
)
|
||||
search_results = verified_results[:limit]
|
||||
|
||||
# Convert SearchResult objects to SemanticSearchResult for response.
|
||||
|
||||
Reference in New Issue
Block a user