Files
rengine/shared/services/asset_query/scope.py
T
Yogesh OjhaandClaude Opus 5 9be7c1d7cc feat(surface): the five result dimensions become project-wide, not scan-scoped
A pentester asked how to see vulnerabilities and the answer was "open a scan".
Every result surface was scoped to one run, which is a scanner's model rather
than an ASM platform's.

The keystone is QueryScope: the set of scans a query reads — one on a scan
page, the latest covering scan of every target on a project view (a producing
stage succeeded, or rows exist; the rule target_summary already used, now
shared as covering_stages()). scope.match() emits `== id` for a single scan so
no scan-page plan changed, and the predicates accept a UUID, a QueryScope or a
sequence so single-scan callers were untouched.

Because the scope generalises rather than duplicates, the same table components
render both views: the grammar, facets, leads, group-by, evidence and detail
sheets all follow. No results table exists twice.

Scan-level facts had to become per-row: _per_scan() ORs and_(col == sid,
build(sid)) so *_has_baseline — and therefore is:new — stays exact across many
scans, and baselined_targets() makes the row-level is_new flag ask per target,
or a first-scanned target badges everything New. Addresses are the exception:
the IPs view folds one row per address across every target that serves it, so
newness is judged against target_ids with the row's own first_seen as cutoff.

- target: is a field in all five grammars and a group dimension in all five
- /surface/[dimension] renders from SURFACE_ORDER; routeLabels take their five
  labels from it so nav, breadcrumb and heading cannot drift
- a scope strip states how many targets the reading covers, how old the oldest
  is, and which targets were never scanned for that dimension, with a launch
  action — absent is not empty
- anything needing a parent run (rescan, recheck, the endpoints Gone lens) is
  off project-wide, and the coverage strips drop their "on this scan" copy
- the scan page's tab strip links to the same dimension across all targets,
  carrying the typed query

Verified: every group token and every counted lead in all five dimensions
returns exactly its own count in both scopes, and project-scoped is:new equals
the union of the per-scan answers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EQgatRaA9fNsv2jXh4rZ47
2026-09-09 05:34:37 +05:30

48 lines
1.1 KiB
Python

from __future__ import annotations
from collections.abc import Sequence
from dataclasses import dataclass
from uuid import UUID
from sqlalchemy import false
@dataclass(frozen=True)
class QueryScope:
"""The scans a query reads: one on a scan page, one per target on a project view."""
ids: tuple[UUID, ...]
project_id: UUID | None = None
@classmethod
def of(cls, value: ScopeLike) -> QueryScope:
if isinstance(value, QueryScope):
return value
if isinstance(value, UUID):
return cls((value,))
return cls(tuple(value))
@property
def single(self) -> UUID | None:
return self.ids[0] if len(self.ids) == 1 else None
def match(self, column):
if not self.ids:
return false()
one = self.single
return column == one if one is not None else column.in_(self.ids)
def __bool__(self) -> bool:
return bool(self.ids)
ScopeLike = UUID | QueryScope | Sequence[UUID]
def scope_of(value: ScopeLike) -> QueryScope:
return QueryScope.of(value)
def scan_filter(column, value: ScopeLike):
return QueryScope.of(value).match(column)