Files
rengine/shared/services/surface_query/web_assets.py
T
Yogesh OjhaandClaude Opus 5 3075ad3ddf refactor(surface): one definition of each dimension's filtered set
The five search services build their statement with pure, session-free
helpers — _context, _apply_filter, _order, _scoped — and then enrich the
page asynchronously. Only the enrichment needs the api. Moving the
builders to shared/services/surface_query lets the worker compile the
same filtered set the table shows, which an export has to do and could
not reach from worker/app.

Web assets gains the _scoped it never had: its base statement was
inlined in search, leads, seeds and renders, so a predicate could drift
between the rows a query returns and the rows its leads count. The four
now read one definition.

No behaviour change. Every route over the moved builders — search,
leads, groups, renders and facets across all five dimensions — was
exercised against a live scan.

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

103 lines
3.3 KiB
Python

"""Web asset statement building, shared by the api's search and the worker's export."""
from __future__ import annotations
from typing import TYPE_CHECKING
from sqlalchemy import cast, func, or_, select
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.dialects.postgresql import array as pg_array
from shared.definitions.asset_query import HOST_QUERY
from shared.models.port import Port
from shared.models.subdomain import Subdomain
from shared.services.asset_query import (
QueryContext,
QueryScope,
ScopeLike,
compile_query,
parse_query,
)
from shared.services.asset_query import (
predicates as preds,
)
if TYPE_CHECKING:
from datetime import datetime
from uuid import UUID
from shared.models.subdomain import SubdomainFilter
def context(scope: QueryScope, now: datetime) -> QueryContext:
return QueryContext(scope=scope, now=now)
def apply_filter(query, f: SubdomainFilter, now: datetime, scope: ScopeLike):
if f.statuses:
query = query.where(or_(*[preds.status_class(s) for s in f.statuses]))
if f.tech:
query = query.where(
func.jsonb_exists_any(cast(Subdomain.tech, JSONB), pg_array(f.tech))
)
if f.sources:
query = query.where(
func.jsonb_exists_any(cast(Subdomain.sources, JSONB), pg_array(f.sources))
)
if f.cert:
query = query.where(or_(*[preds.cert_state(c, now) for c in f.cert]))
if f.hygiene:
query = query.where(preds.hygiene(f.hygiene))
if f.services:
query = query.where(preds.port_match(Port.service_name.in_(f.services), scope))
if f.cdn == "yes":
query = query.where(Subdomain.is_cdn.is_(True))
elif f.cdn == "no":
query = query.where(Subdomain.is_cdn.is_(False))
if f.waf == "present":
query = query.where(Subdomain.waf.isnot(None))
elif f.waf == "none":
query = query.where(Subdomain.waf.is_(None))
if f.live:
query = query.where(preds.live())
if f.screenshot:
query = query.where(Subdomain.screenshot_path.isnot(None))
if f.new:
query = query.where(preds.is_new(scope))
if f.issues:
query = query.where(preds.issues(now))
return query
def order(query, f: SubdomainFilter):
col = {
"status": Subdomain.http_status,
"size": Subdomain.content_length,
"time": Subdomain.response_time,
"title": Subdomain.page_title,
"cert": Subdomain.tls_not_after,
"discovered": Subdomain.discovered_at,
"ip": cast(Subdomain.resolved_ips, JSONB).op("->>")(0),
}.get(f.sort, Subdomain.name)
primary = col.desc() if f.order == "desc" else col.asc()
return query.order_by(primary.nulls_last(), Subdomain.name.asc())
def scoped(
project_id: UUID,
scope: QueryScope,
f: SubdomainFilter,
now: datetime,
columns=None,
):
"""The one definition of the filtered host set. Was inlined four times."""
base = select(Subdomain) if columns is None else select(*columns)
base = base.where(
Subdomain.project_id == project_id, scope.match(Subdomain.scan_id)
)
return apply_filter(base, f, now, scope)
def compiled(scope: QueryScope, f: SubdomainFilter, now: datetime):
return compile_query(parse_query(f.q, HOST_QUERY), context(scope, now))