Repository navigation
Releases
Releases · lichti/ogum-security
v0.2.0 — Epic 14 UX Avançado, Scans page, compliance redesign
Added
- New
/scanspage (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:ScanJobgainedfindings_new/findings_updated/findings_removed/assets_total/assets_removed/duration_seconds, computed inrun_cspm_scan(workers/tasks/cspm_scan.py) —_soft_delete_stalenow returns the deletedresource_ids per collection, a new_cascade_delete_findingshard-deletes findings whose resource was just soft-deleted this run (sweeping theirHAS_FINDINGedges), and_count_new_and_updated_findingsreads the pre-existingfirst_seen_scan_id/scan_countfields.scan_service.py(rewritten) adds keyset-paginatedlist_scan_jobs(status/provider filters) andget_scan_job_logs, both scoped to CSPM jobs only (task_namestarting withcspm_scan/) sincescan_jobsis shared with Side-Scanning's differently-shaped documents. NewGET /api/v1/scans(paginated) andGET /api/v1/scans/{job_id}/logs. - Semantic
id/data-testidattributes and a shared page-header pattern applied across the entire frontend, adopted as the standing convention (documented inCLAUDE.md): structural elements (page root, major sections, cards/panels, tables, forms) carry anidwhen unique per page or adata-testidwhen repeated via.map(); a page's title and one-line description now live in the top bar (Header.tsx'sROUTE_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.pyloads the full AWS requirement catalog for every compliance framework at runtime via theprowlerpackage's ownCompliance.get_bulk("aws")(not vendored JSON), computing the same{Framework}-{Version}slug Prowler already embeds inFinding.framework_mapping— verified byte-identical againstresolve_family()'s existing slug table.GET /api/v1/compliance/frameworks/{id}(new) returnsscore_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 asscore_by_asset, plusunscored_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 afinding_keylink) that backs both the newSectionHeatmap(color-coded ≥80/50–79/<50, reusingScoreGauge's existing thresholds) andRequirementAccordion(plain React state, no shadcn — see Fixed below) components. A newcompliance_score_snapshotscollection, written bysnapshot_compliance_scoresat the end of everyrun_cspm_scan(any provider, upserted by tenant+framework+day — no backfill), backsGET /api/v1/compliance/frameworks/{id}/trend?period=7d|14d|1mand the newScoreTrendChart(first realrechartsusage in the project; categorical color pair validated with the dataviz skill's palette validator against the dark chart surface). The catalog — and thereforescore_by_control/Unscored— is AWS-only (decision #14 scope); non-AWS frameworks still getscore_by_assetand a trend, surfaced viacatalog_available: falserather than a fabricated Unscored count. Follow-up in the same batch:MUTED/ACCEPTEDfindings, 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 thescore_by_assetratio) — surfaced via a "By Control / By Findings" toggle above the summary row and eachSectionHeatmaprow, 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-pathsand/statsnow enrich every row withtarget_asset_category(server-sideDOCUMENT()join + a newresource_categories.py, a direct Python port ofinventoryCategories.tskept in lockstep) andtarget_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, elsemanually_flagged;nullwhen 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.AttackPathListis 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-pathsreorders the same underlying path list by a different second-level key (target_asset_categoryfor Paths/Assets, detectionrulefor Alerts) — no new endpoint, per the decision to keep one search engine behind all three views.AttackPathCanvasgained a syntheticriskInsightnode type (amber, dotted edge, ⊕/🔒 status badge) attached per-resource from the path's associated findings via a newattachRiskInsightNodeshelper ingraph-layout.ts.build_attack_path_docsnow persistsexposure(internet_facing/public_facing/trusted_access/none, via a newclassify_path_exposureingraph/exposure.py),is_cross_account,is_cross_cloud_provider, andaccount_idson every detected path; a newGET /api/v1/attack-paths/{path_id}/narrativereturns a deterministic 4-step paginated narrative (attack_path_narrative_service.py, same template-onlygenerated_bycontract as US-14.02'sResourceNarrativeSummary— 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 onattack_pathsyet) and aTake Actionmenu (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 InventoryandCompliancetabs now render real data.GET /api/v1/inventory/{resource_key}/softwarederives Installed Packages (name, version, linked CVE ids, filesystem path when Trivy exposes it) and Licenses (SPDX id, category via a newlicense_catalog.pypermissive/copyleft/weak-copyleft table, deprecated-id flag) from the CycloneDX SBOM already produced by Side-Scanning (Epic 03); theApplications/Running Servicessub-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}/complianceadds a per-resource framework selector + control table, reusingcompliance_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/slapage) backs aGET /api/v1/findings/sla-summaryaggregate panel andSLABadgewired 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 frontendclassifySLAhelper, kept in lockstep insla_service.py);GET /api/v1/findings/{key}/exposure-pathadds a mini blast-radius graph to the finding detail panel, reusinginventory_detail_service.get_blast_radiusrather than duplicating the AQL traversal; and a Timeline section shows first-detection date and a newscan_countre-scan counter.first_seen_scan_id/last_seen_scan_id/scan_countare newFindingfields, populated by a newupsert_finding()helper (workers/tasks/cloud_utils.py) that replaces the ad-hoc upsert previously duplicated incspm_scan.pyandside_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_newbadge/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...