Skip to content

Releases

v0.2.0 — Epic 14 UX Avançado, Scans page, compliance redesign

Choose a tag to compare

@lichti lichti released this 25 Aug 20:06
b502478

Added

  • New /scans page (Configuration): registers and lists every CSPM scan job — job id, provider, frameworks, start/end/duration, checks completed, and a findings/assets summary (new/updated/removed, total assets, assets removed) — with status pill filters (queued/running/completed/failed, all selected by default), cursor pagination, and a "Trigger Scan" modal picking any connected provider. Finished jobs (completed/failed) show a "View Logs" button opening the raw execution log. Backend: ScanJob gained findings_new/findings_updated/findings_removed/assets_total/assets_removed/duration_seconds, computed in run_cspm_scan (workers/tasks/cspm_scan.py) — _soft_delete_stale now returns the deleted resource_ids per collection, a new _cascade_delete_findings hard-deletes findings whose resource was just soft-deleted this run (sweeping their HAS_FINDING edges), and _count_new_and_updated_findings reads the pre-existing first_seen_scan_id/scan_count fields. scan_service.py (rewritten) adds keyset-paginated list_scan_jobs (status/provider filters) and get_scan_job_logs, both scoped to CSPM jobs only (task_name starting with cspm_scan/) since scan_jobs is shared with Side-Scanning's differently-shaped documents. New GET /api/v1/scans (paginated) and GET /api/v1/scans/{job_id}/logs.
  • Semantic id/data-testid attributes and a shared page-header pattern applied across the entire frontend, adopted as the standing convention (documented in CLAUDE.md): structural elements (page root, major sections, cards/panels, tables, forms) carry an id when unique per page or a data-testid when repeated via .map(); a page's title and one-line description now live in the top bar (Header.tsx's ROUTE_LABELS/ROUTE_SUBTITLES) instead of a local <h1>/<p> duplicated in every page body.
  • Epic 14 Sprint 4, Compliance Avançado batch (UX Avançado II — score duality, section heatmap, score trend, nested requirement drill-down): a new compliance_catalog.py loads the full AWS requirement catalog for every compliance framework at runtime via the prowler package's own Compliance.get_bulk("aws") (not vendored JSON), computing the same {Framework}-{Version} slug Prowler already embeds in Finding.framework_mapping — verified byte-identical against resolve_family()'s existing slug table. GET /api/v1/compliance/frameworks/{id} (new) returns score_by_control (fraction of controls with zero failing assets, Unscored controls excluded from the denominator) alongside the pre-existing finding-count-based score, now exposed as score_by_asset, plus unscored_count (catalog controls with no PASS/FAIL finding yet for the tenant) and a section → sub-section → requirement tree (each requirement carries PASS/FAIL/UNSCORED status and a finding_key link) that backs both the new SectionHeatmap (color-coded ≥80/50–79/<50, reusing ScoreGauge's existing thresholds) and RequirementAccordion (plain React state, no shadcn — see Fixed below) components. A new compliance_score_snapshots collection, written by snapshot_compliance_scores at the end of every run_cspm_scan (any provider, upserted by tenant+framework+day — no backfill), backs GET /api/v1/compliance/frameworks/{id}/trend?period=7d|14d|1m and the new ScoreTrendChart (first real recharts usage in the project; categorical color pair validated with the dataviz skill's palette validator against the dark chart surface). The catalog — and therefore score_by_control/Unscored — is AWS-only (decision #14 scope); non-AWS frameworks still get score_by_asset and a trend, surfaced via catalog_available: false rather than a fabricated Unscored count. Follow-up in the same batch: MUTED/ACCEPTED findings, previously dropped silently by every compliance query (FILTER f.status IN ["FAIL", "PASS"]), are now tracked explicitly. GET /api/v1/compliance/frameworks/{id} and its section tree carry two parallel breakdowns — Control view (control_pass_count/control_fail_count/control_unscored_count/control_total, where an ACCEPTED-only control folds into Pass and a MUTED-only control folds into Unscored — a control's status is FAIL if any asset fails it, else PASS if any asset passes or has accepted risk, else Unscored) and Findings view (finding_pass_count/finding_fail_count/finding_accepted_count/finding_muted_count, the real per-finding-status counts, both ACCEPTED and MUTED excluded from the score_by_asset ratio) — surfaced via a "By Control / By Findings" toggle above the summary row and each SectionHeatmap row, switching client-side against data already fetched in one request rather than refetching per toggle.
  • Epic 14 Sprint 4, Attack Paths batch (UX Avançado II — hierarchical path list, View Results By toggle, path narrative): GET /api/v1/attack-paths and /stats now enrich every row with target_asset_category (server-side DOCUMENT() join + a new resource_categories.py, a direct Python port of inventoryCategories.ts kept in lockstep) and target_crown_jewel_reason (derived from real signals only — is_public/exposed_internet → internet_facing, contains_credentials/contains_secrets → stores_sensitive_data, has_admin_policy → high_privilege_identity, else manually_flagged; null when the target isn't a crown jewel), both computed at read time rather than persisted since crown-jewel status can change out-of-band between path-detection runs; both are also new list filters and stats dimensions. AttackPathList is now a 2-level expandable tree (severity → category, both expanded by default with per-level counts), and a "View Results By: Paths / Alerts / Assets" toggle on /attack-paths reorders the same underlying path list by a different second-level key (target_asset_category for Paths/Assets, detection rule for Alerts) — no new endpoint, per the decision to keep one search engine behind all three views. AttackPathCanvas gained a synthetic riskInsight node type (amber, dotted edge, ⊕/🔒 status badge) attached per-resource from the path's associated findings via a new attachRiskInsightNodes helper in graph-layout.ts. build_attack_path_docs now persists exposure (internet_facing/public_facing/trusted_access/none, via a new classify_path_exposure in graph/exposure.py), is_cross_account, is_cross_cloud_provider, and account_ids on every detected path; a new GET /api/v1/attack-paths/{path_id}/narrative returns a deterministic 4-step paginated narrative (attack_path_narrative_service.py, same template-only generated_by contract as US-14.02's ResourceNarrativeSummary — Epic 05/Ogum.AI-RAG still isn't implemented). The path detail bottom bar gained a "Path Info" section (status, created, length, copyable ID, ExposureBadge, cross-account/cross-cloud, accounts — "Status Changed" is an explicit "not available yet", there's no status-transition history on attack_paths yet) and a Take Action menu (Export path and View each resource are functional; Generate remediation PR is disabled, Epic 05 dependency). Removed the Epic 02 Sprint 2 table-based Attack Paths components (AttackPathsTable.tsx, AttackPathFilters.tsx, AttackPathDetailPanel.tsx) — dead code superseded by the React Flow canvas UI, unused by any page since the canvas redesign.
  • Epic 14 Sprint 3 (UX Avançado II — Software Inventory, Resource Compliance, Findings SLA/Exposure/Timeline): the Inventory detail panel's Software Inventory and Compliance tabs now render real data. GET /api/v1/inventory/{resource_key}/software derives Installed Packages (name, version, linked CVE ids, filesystem path when Trivy exposes it) and Licenses (SPDX id, category via a new license_catalog.py permissive/copyleft/weak-copyleft table, deprecated-id flag) from the CycloneDX SBOM already produced by Side-Scanning (Epic 03); the Applications/Running Services sub-tabs show an explicit "not available yet" state since no pipeline in the platform produces that data yet (documented gap, not fabricated). GET /api/v1/inventory/{resource_key}/compliance adds a per-resource framework selector + control table, reusing compliance_service.py's family/section resolution logic scoped to one resource's findings. On Findings: a configurable per-severity remediation SLA (GET/PUT /api/v1/settings/sla, defaults CRITICAL 7d/HIGH 30d/MEDIUM 90d/LOW 180d, new /settings/sla page) backs a GET /api/v1/findings/sla-summary aggregate panel and SLABadge wired into the findings table and detail panel (the SLA classification logic — overdue past deadline, at-risk within 20% of the remaining window — is a direct Python port of the existing frontend classifySLA helper, kept in lockstep in sla_service.py); GET /api/v1/findings/{key}/exposure-path adds a mini blast-radius graph to the finding detail panel, reusing inventory_detail_service.get_blast_radius rather than duplicating the AQL traversal; and a Timeline section shows first-detection date and a new scan_count re-scan counter. first_seen_scan_id/last_seen_scan_id/scan_count are new Finding fields, populated by a new upsert_finding() helper (workers/tasks/cloud_utils.py) that replaces the ad-hoc upsert previously duplicated in cspm_scan.py and side_scanning.py — a small, deliberately scoped pull-forward of Epic 12's US-12.06 (only the scan-history fields, not the grouped view/is_new badge/bulk-mute that story also covers).
  • Epic 14 Sprint 2 (UX Avançado II — Inventory detail panel): the Inventory detail panel is rewritten as a two-tier tab system (Info | Risk | Network | IAM | Configurations | Software Inventory | Compliance, each with sub-tabs), ~58% viewport width instead of a 420px drawer, with breadcrumb, Scan Now/Open in Console/kebab (Copy ARN/Resource ID) actions, keyboard-navigable tabs (roving tabindex, arrow keys), and deep-linkable state via ?tab=&subtab= querystring. `Info > Ove...
Read more