Skip to content

Guide users when vulnerability scanning is disabled or misconfigured, and show the next scheduled run #168

Description

@LarsLaskowski

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", …).
  • The scan-history page already reads 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).
  • Scheduling: Images/VulnerabilityRefreshBackgroundService.cs derives its interval from options; scan runs are persisted as ScanRun rows with Type == ScanRunType.Vulnerability.

Desired behavior

  1. 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."
  2. 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/Failed and its ErrorMessage contains the provider's not-configured text), show a Severity.Warning alert on the dashboard naming the missing setting: for TrivyTrivyBaseUrl; for DockerScoutDockerHub:UserName / DockerHub:Pat. Keep the heuristic in one testable helper.
  3. 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.
  • reihitsu-format ./ clean, dotnet build DockerUpdateGuard.slnx -c Release clean, all tests pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions