diff --git a/src/Backend/AutopilotMonitor.Functions/DataAccess/TableStorage/TableVulnerabilityRepository.cs b/src/Backend/AutopilotMonitor.Functions/DataAccess/TableStorage/TableVulnerabilityRepository.cs index f88141c1..94aa0f59 100644 --- a/src/Backend/AutopilotMonitor.Functions/DataAccess/TableStorage/TableVulnerabilityRepository.cs +++ b/src/Backend/AutopilotMonitor.Functions/DataAccess/TableStorage/TableVulnerabilityRepository.cs @@ -39,6 +39,11 @@ namespace AutopilotMonitor.Functions.DataAccess.TableStorage public Task GetVulnerabilityReportJsonAsync(string tenantId, string sessionId) => _storage.GetVulnerabilityReportJsonAsync(tenantId, sessionId); + public async Task DeleteVulnerabilityReportAsync(string tenantId, string sessionId) + { + await _storage.DeleteVulnerabilityReportAsync(tenantId, sessionId); + } + // --- Software Inventory --- public Task UpsertSoftwareInventoryAsync(string tenantId, List> inventoryItems, diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/Vulnerability/GetVulnerabilityReportFunction.cs b/src/Backend/AutopilotMonitor.Functions/Functions/Vulnerability/GetVulnerabilityReportFunction.cs index b4b6b87a..b2bebb23 100644 --- a/src/Backend/AutopilotMonitor.Functions/Functions/Vulnerability/GetVulnerabilityReportFunction.cs +++ b/src/Backend/AutopilotMonitor.Functions/Functions/Vulnerability/GetVulnerabilityReportFunction.cs @@ -96,6 +96,15 @@ namespace AutopilotMonitor.Functions.Functions.Vulnerability await rescanResponse.WriteAsJsonAsync(new { success = true, sessionId, report = freshReport, rescanned = true }); return rescanResponse; } + + // Rescan found no vulnerabilities — clear the stale report so the + // UI no longer shows outdated findings from a previous scan. + await _vulnRepo.DeleteVulnerabilityReportAsync(effectiveTenantId, sessionId); + _logger.LogInformation("Vulnerability re-scan complete for session {SessionId}: no findings, cleared old report", sessionId); + + var noFindingsResponse = req.CreateResponse(HttpStatusCode.OK); + await noFindingsResponse.WriteAsJsonAsync(new { success = true, sessionId, report = (object?)null, rescanned = true, message = "Re-scan complete: no vulnerabilities found" }); + return noFindingsResponse; } catch (Exception ex) { diff --git a/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Rules.cs b/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Rules.cs index b8e55a9d..363040a7 100644 --- a/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Rules.cs +++ b/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Rules.cs @@ -553,6 +553,28 @@ namespace AutopilotMonitor.Functions.Services scanSummary?.GetValueOrDefault("overall_risk")?.ToString() ?? "none"); } + /// + /// Deletes the stored vulnerability report for a session. + /// Used when a re-scan finds no vulnerabilities, to clear stale data. + /// + public async Task DeleteVulnerabilityReportAsync(string tenantId, string sessionId) + { + SecurityValidator.EnsureValidGuid(tenantId, nameof(tenantId)); + SecurityValidator.EnsureValidGuid(sessionId, nameof(sessionId)); + + try + { + var tableClient = _tableServiceClient.GetTableClient(Constants.TableNames.VulnerabilityReports); + var partitionKey = $"{tenantId}_{sessionId}"; + await tableClient.DeleteEntityAsync(partitionKey, "report"); + _logger.LogInformation("Deleted vulnerability report for session {SessionId}", sessionId); + } + catch (Azure.RequestFailedException ex) when (ex.Status == 404) + { + // Already deleted or never existed — nothing to do + } + } + /// /// Gets the vulnerability correlation report for a session. /// Returns the deserialized report data, or null if no report exists. diff --git a/src/Shared/AutopilotMonitor.Shared/DataAccess/IVulnerabilityRepository.cs b/src/Shared/AutopilotMonitor.Shared/DataAccess/IVulnerabilityRepository.cs index 708513b9..869de008 100644 --- a/src/Shared/AutopilotMonitor.Shared/DataAccess/IVulnerabilityRepository.cs +++ b/src/Shared/AutopilotMonitor.Shared/DataAccess/IVulnerabilityRepository.cs @@ -18,6 +18,7 @@ namespace AutopilotMonitor.Shared.DataAccess /// to avoid Newtonsoft JToken serialization issues. /// Task GetVulnerabilityReportJsonAsync(string tenantId, string sessionId); + Task DeleteVulnerabilityReportAsync(string tenantId, string sessionId); // --- Software Inventory --- Task UpsertSoftwareInventoryAsync(string tenantId, List> inventoryItems,