Files
rengine/tests/api/test_dashboard_activity.py
T
Yogesh OjhaandClaude Fable 5.1 f237e3da4f feat(dashboard): rebuild the project dashboard as a bento of hairline cells
Four bands in reading order: counts, the attack surface funnel beside
geography and the added/retired changes chart beside inventory, an
Act/Attend/Track findings board with severity per day, exploitation and
an evidence matrix, a mode band (platform events, watched programs and
browsing in bug bounty mode; certificates, hygiene and ownership in
corporate mode), scan activity and software CVEs, composition cells, and
an activity rail. The 7d/14d/30d window redraws every time chart; every
cell can be hidden and restored per mode from a catalog.

The overview gains the funnel, retired rows per day, findings per day by
severity, run outcomes per day, the severity by evidence matrix, queue
tiers and certificate expiry buckets. GET /dashboard/activity unions runs,
feeds, exploitation changes, connector syncs and, in bug bounty mode,
watch and platform events. GET /dashboard/programs carries the bug bounty
band.

Copy states a measure or nothing. Counts tiles open a per-target sheet
with a scan action, funnel steps hint and dim on hover, board cards open
a hover card.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjHnxAPLMDSfQgVQDfDYBj
2026-09-14 16:20:24 +05:30

42 lines
1.2 KiB
Python

from __future__ import annotations
from datetime import timedelta
import pytest
from app.services.dashboard_activity import DashboardActivityService
pytestmark = pytest.mark.api
async def test_runs_land_on_the_rail_newest_first(estate, now):
await estate.scan("example.com", "older", at=now - timedelta(days=2))
await estate.scan(
"example.com", "broken", at=now - timedelta(hours=1), status="failed"
)
await estate.scan("example.com", "fresh", at=now)
await estate.hosts("fresh", ["a.example.com"], at=now)
out = await DashboardActivityService(estate.session).activity(
estate.project_id, "7d", programs=False
)
runs = [e for e in out.events if e.kind == "run"]
assert [e.title for e in runs] == [
"example.com run completed",
"example.com run failed",
"example.com run completed",
]
assert runs[1].tone == "hot"
assert runs[0].scan_id == estate.scans["fresh"]
async def test_the_window_cuts_the_rail(estate, now):
await estate.scan("example.com", "old", at=now - timedelta(days=10))
out = await DashboardActivityService(estate.session).activity(
estate.project_id, "7d", programs=False
)
assert out.events == []