You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Builds on the vulnerability rework in PR #164. Read CLAUDE.md and .github/instructions/csharp.instructions.md first — the code-style rules there (regions, XML docs on everything, == false instead of !, aligned wrapped parameters, MSTest assertion messages, reihitsu-format ./ before building) are binding.
Background
When vulnerability scanning is disabled (DockerUpdateGuard:Vulnerabilities:Enabled = false) or the configured provider reports NotConfigured (e.g. Docker Scout without Docker Hub credentials, Trivy without TrivyBaseUrl), the UI today only shows quiet "Not scanned" / "Not configured" chips. A user who wants scanning has no hint what to configure, and a user with scanning enabled cannot see when the next automatic run will happen.
Relevant code:
Options: src/DockerUpdateGuard/Configuration/VulnerabilityOptions.cs, interval in Configuration/ScanningOptions.cs (VulnerabilityRefreshIntervalMinutes).
Status formatting: ApplicationViewService.FormatVulnerabilityAssessmentStatus ("Not scanned", "Not configured", "Unsupported", …).
Scheduling: Images/VulnerabilityRefreshBackgroundService.cs derives its interval from options; scan runs are persisted as ScanRun rows with Type == ScanRunType.Vulnerability.
Desired behavior
Dashboard info banner: when Vulnerabilities:Enabled == false, show a dismiss-free, dense MudAlert (Severity.Info) under the metric cards on Dashboard.razor: "Vulnerability scanning is disabled. Set DockerUpdateGuard:Vulnerabilities:Enabled to true and configure a provider (Trivy or DockerScout) to see security findings."
Provider misconfiguration banner: when scanning is enabled but the most recent vulnerability scan run ended with every image NotConfigured (heuristic: the latest completed ScanRun of type Vulnerability has status Partial/Failedand its ErrorMessage contains the provider's not-configured text), show a Severity.Warning alert on the dashboard naming the missing setting: for Trivy → TrivyBaseUrl; for DockerScout → DockerHub:UserName / DockerHub:Pat. Keep the heuristic in one testable helper.
Next scheduled run: on the scan-history page header (next to the manual refresh button added in PR Rework vulnerability integration: finding upsert, richer advisory data, severity-aware UI, manual refresh #164) show "Next scheduled vulnerability refresh: {time}" when scanning is enabled. Compute it as lastVulnerabilityRunStartedAtUtc + VulnerabilityRefreshIntervalMinutes; when no run exists yet, show "Next scheduled vulnerability refresh: shortly (no run recorded yet)". Note the background scheduler does not persist its exact timer, so this is an estimate — label the UI value exactly as specified so it is not read as a guarantee.
Implementation guidance
View data: extend UI/DashboardViewData.cs with bool VulnerabilityScanningEnabled, string? VulnerabilityConfigurationHint (null when nothing to show), and extend the scan-history flow with DateTimeOffset? NextVulnerabilityRefreshUtc — either on a small new view data class returned by a dedicated IApplicationViewService method or piggybacked where the page already loads data. ApplicationViewService does not currently read options; inject IOptionsMonitor<DockerUpdateGuardOptions> there (constructor injection, private readonly field, follow the DI conventions).
Banner texts belong in the razor markup, not in the service; the service only supplies the state (enabled flag, hint kind). Prefer an enum UI/VulnerabilityConfigurationHintKind.cs (None, ScanningDisabled, TrivyBaseUrlMissing, DockerHubCredentialsMissing) over free-text from the service, then map to text in the page. Enum values individually XML-documented, first value None = 0.
Dashboard: render the alerts under the MudGrid of metric cards; look at existing MudAlert usage in RuntimeContainers.razor for styling.
Times: render with .ToLocalTime().ToString("g") like every other timestamp in the codebase.
Acceptance criteria
Disabled scanning → info banner on the dashboard; enabled scanning → no banner.
Enabled but misconfigured provider → warning banner naming the concrete missing setting; correctly configured → no banner.
Scan-history header shows the estimated next scheduled refresh (or the no-run-yet variant) when scanning is enabled, and nothing when disabled.
ApplicationViewServiceTests cover the hint-kind resolution (disabled / trivy-missing / scout-credentials-missing / configured) and the next-run computation from a seeded ScanRun. bUnit tests cover banner rendering on the dashboard for at least the disabled case. Follow {Class}{Scenario}{ExpectedResult} naming with assertion messages.
Background
When vulnerability scanning is disabled (
DockerUpdateGuard:Vulnerabilities:Enabled = false) or the configured provider reportsNotConfigured(e.g. Docker Scout without Docker Hub credentials, Trivy withoutTrivyBaseUrl), the UI today only shows quiet "Not scanned" / "Not configured" chips. A user who wants scanning has no hint what to configure, and a user with scanning enabled cannot see when the next automatic run will happen.Relevant code:
src/DockerUpdateGuard/Configuration/VulnerabilityOptions.cs, interval inConfiguration/ScanningOptions.cs(VulnerabilityRefreshIntervalMinutes).ApplicationViewService.FormatVulnerabilityAssessmentStatus("Not scanned", "Not configured", "Unsupported", …).IOptionsMonitor<DockerUpdateGuardOptions>and hides its manual refresh button when disabled (Components/Pages/ScanHistory.razor(.cs), since PR Rework vulnerability integration: finding upsert, richer advisory data, severity-aware UI, manual refresh #164).Images/VulnerabilityRefreshBackgroundService.csderives its interval from options; scan runs are persisted asScanRunrows withType == ScanRunType.Vulnerability.Desired behavior
Vulnerabilities:Enabled == false, show a dismiss-free, denseMudAlert(Severity.Info) under the metric cards onDashboard.razor:"Vulnerability scanning is disabled. Set
DockerUpdateGuard:Vulnerabilities:Enabledtotrueand configure a provider (TrivyorDockerScout) to see security findings."NotConfigured(heuristic: the latest completedScanRunof typeVulnerabilityhas statusPartial/Failedand itsErrorMessagecontains the provider's not-configured text), show aSeverity.Warningalert on the dashboard naming the missing setting: forTrivy→TrivyBaseUrl; forDockerScout→DockerHub:UserName/DockerHub:Pat. Keep the heuristic in one testable helper.lastVulnerabilityRunStartedAtUtc + VulnerabilityRefreshIntervalMinutes; when no run exists yet, show "Next scheduled vulnerability refresh: shortly (no run recorded yet)". Note the background scheduler does not persist its exact timer, so this is an estimate — label the UI value exactly as specified so it is not read as a guarantee.Implementation guidance
UI/DashboardViewData.cswithbool VulnerabilityScanningEnabled,string? VulnerabilityConfigurationHint(null when nothing to show), and extend the scan-history flow withDateTimeOffset? NextVulnerabilityRefreshUtc— either on a small new view data class returned by a dedicatedIApplicationViewServicemethod or piggybacked where the page already loads data.ApplicationViewServicedoes not currently read options; injectIOptionsMonitor<DockerUpdateGuardOptions>there (constructor injection, private readonly field, follow the DI conventions).UI/VulnerabilityConfigurationHintKind.cs(None,ScanningDisabled,TrivyBaseUrlMissing,DockerHubCredentialsMissing) over free-text from the service, then map to text in the page. Enum values individually XML-documented, first valueNone = 0.MudGridof metric cards; look at existingMudAlertusage inRuntimeContainers.razorfor styling..ToLocalTime().ToString("g")like every other timestamp in the codebase.Acceptance criteria
ApplicationViewServiceTestscover the hint-kind resolution (disabled / trivy-missing / scout-credentials-missing / configured) and the next-run computation from a seededScanRun. bUnit tests cover banner rendering on the dashboard for at least the disabled case. Follow{Class}{Scenario}{ExpectedResult}naming with assertion messages.reihitsu-format ./clean,dotnet build DockerUpdateGuard.slnx -c Releaseclean, all tests pass.