mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-20 15:21:30 +02:00
reports/narrate/ai.py instructs the model: no marketing language, no hedging,
no filler, never an em dash, never a rhetorical question. The product broke all
three. There was a house style in this repository and it applied only to the
machine.
The activity feed printed Python dictionary keys. stage_count_summary rendered
key.replace('_', ' ') over StageResult.counts, so a live scan read "12 waf,
340 checked", "88 ptr", "412 http assets", "56 alive". _STAGE_COUNT_LABELS now
covers all 31 count keys with singular and plural, and an unlabelled key is
dropped rather than printed raw, so a new stage can never leak one again.
Errors had three registers: "Failed to X" (121), "Could not X" (28), and
"Couldn't X - try again" (6), alongside a passive form the result tables already
used. All of it is now "<Subject> could not be <verbed>", which names the thing
that failed before the failure. The rate limiter reads the key's TTL and says
how long to wait instead of "Please wait a moment".
Onboarding fired confetti and a party popper, opened with "Let's get your
instance set up", and asked an operator to tick "I've saved my backup codes".
confetti.ts is deleted.
Casing was split down the middle: the sidebar group read "Attack surface" while
the item under it read "Scheduled Scans", and page headings restated the nav in
Title Case. Sentence case throughout now, including SURFACE_LABELS, so the
backend and its mirror agree.
The KEV sentence in generated reports claimed a listing "means working exploit
code is public". It means exploitation has been observed in the wild. That one
printed under a client's letterhead.
Also: 18 "This action cannot be undone" in three spellings removed in favour of
the concrete consequence; every em dash, contraction and "Please" out of user
copy; surface vocabulary applied to alerts and the notification settings, not
only the result tables; the "X, not Y" antithesis thinned from ten uses to the
two that carry a real distinction; advice copy ("fix first", "worth a look",
"Add to renewal watchlist", which named a feature that does not exist) reduced
to the fact.
Nine rules are written up in the audit linked below and hold for new copy.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LM9TbCGhGb4s6nag6PsuaT
48 lines
1.6 KiB
Python
48 lines
1.6 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: "IPs",
|
|
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}
|
|
),
|
|
}
|