Files
rengine/shared/definitions/surface.py
T
Yogesh OjhaandClaude Opus 5 8f341131fc refactor(ui): enterprise naming for the navigation, and Interest becomes Exposures
The menu read as hacker cosplay rather than security software: "Worth a look"
as a product feature, swords for the tool library, a sparkle for a risk
surface, a crosshair for the asset list.

"Worth a look" is now Exposures. Studying what the layer does settles the name:
it scores an asset for what it IS — admin interface, developer tooling, remote
access, non-production, legacy, no authentication, exposed content, takeover
risk — and for how far it stands out from the estate. That is an exposure, the
Gartner CTEM term, and it pairs with Vulnerabilities, which is what a scanner
found. Bands are Critical/High/Notable, not "Look first"/"Worth a look".

Only the user-visible layer is renamed. The interest/ package, the
interest_signals table and InterestKind keep their names because renaming them
is a migration with no user benefit. The host grammar's canonical tokens become
is:exposed, exposure:<kind> and exposure_band:<band>, with the old spellings
kept as aliases so no saved rule breaks — and the endpoint grammar's separate
interest: (open_redirect, traversal, admin) keeps its name, so the rename
removes a collision rather than creating one.

Exposures also stops being a settings page. The nav item opened Rules and
Dismissed while its name promised findings; it now opens the project-wide
ranked list over the same QueryScope as the five dimensions, with Rules and
Dismissed as tabs. Judging and rule suggestions are per-run and stay hidden
there, and a project view reports stale=false so it never queues a re-label.

Naming and icons elsewhere:
- IPs -> IP addresses; the other four dimensions keep their names
- Reconnaissance -> Discovery
- the Services "Exposure" panel -> "Open services", freeing the word
- swords -> library, sparkle -> scan-eye, crosshair -> target, plug-zap ->
  cable, network -> bot for MCP, layers -> sliders for scan contexts, and no
  two items in a group share a glyph

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

57 lines
2.1 KiB
Python

"""The five result dimensions a scan produces, named as the UI names them."""
from __future__ import annotations
from enum import StrEnum
from shared.enums.scan import AssetKind
class SurfaceDimension(StrEnum):
WEB_ASSETS = "web_assets"
ENDPOINTS = "endpoints"
SERVICES = "services"
IPS = "ips"
VULNERABILITIES = "vulnerabilities"
SURFACE_ORDER: tuple[str, ...] = tuple(d.value for d in SurfaceDimension)
SURFACE_LABELS: dict[str, str] = {
SurfaceDimension.WEB_ASSETS.value: "Web assets",
SurfaceDimension.ENDPOINTS.value: "Endpoints",
SurfaceDimension.SERVICES.value: "Services",
SurfaceDimension.IPS.value: "IP addresses",
SurfaceDimension.VULNERABILITIES.value: "Vulnerabilities",
}
SURFACE_NOUN: dict[str, tuple[str, str]] = {
SurfaceDimension.WEB_ASSETS.value: ("web asset", "web assets"),
SurfaceDimension.ENDPOINTS.value: ("endpoint", "endpoints"),
SurfaceDimension.SERVICES.value: ("service", "services"),
SurfaceDimension.IPS.value: ("address", "addresses"),
SurfaceDimension.VULNERABILITIES.value: ("finding", "findings"),
}
# a stage covers a dimension when it produces one of these kinds
SURFACE_KINDS: dict[str, frozenset[str]] = {
SurfaceDimension.WEB_ASSETS.value: frozenset(
{AssetKind.HOSTS.value, AssetKind.HTTP_ASSETS.value}
),
SurfaceDimension.ENDPOINTS.value: frozenset({AssetKind.ENDPOINTS.value}),
SurfaceDimension.SERVICES.value: frozenset({AssetKind.PORTS.value}),
SurfaceDimension.IPS.value: frozenset({AssetKind.ADDRESSES.value}),
SurfaceDimension.VULNERABILITIES.value: frozenset(
{AssetKind.VULNERABILITIES.value}
),
}
# the scans rollup columns a dimension's rows move; the live counter refreshes these
SURFACE_COUNT_COLUMNS: dict[str, tuple[str, ...]] = {
SurfaceDimension.WEB_ASSETS.value: ("subdomains_found", "http_assets_found"),
SurfaceDimension.ENDPOINTS.value: ("endpoints_found",),
SurfaceDimension.SERVICES.value: ("open_ports_found",),
SurfaceDimension.IPS.value: ("ips_found",),
SurfaceDimension.VULNERABILITIES.value: ("vulnerabilities_found",),
}