Skip to content

Support private registries in the Trivy vulnerability provider and document credential handling #171

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

src/DockerUpdateGuard/Vulnerabilities/TrivyVulnerabilityProvider.cs runs the Trivy CLI in client mode (trivy image --server …) via IProcessRunner (Infrastructure/ProcessRunner). The scan target is built from the image reference (GetScanTarget), including non-Docker-Hub registries as registry/repository:tag[@digest]. However, no registry credentials are ever passed to the Trivy process, so scanning images from private registries fails with an authentication error from Trivy — the finding status ends up Failed with a cryptic CLI excerpt.

Trivy supports registry authentication via the environment variables TRIVY_USERNAME and TRIVY_PASSWORD (single registry), and honors the local Docker config when present. See the Trivy docs on private registries.

Task

1. Configuration

Add per-registry credentials to Configuration/VulnerabilityOptions.cs:

/// <summary>
/// Registry credentials used by the Trivy CLI for private registries
/// </summary>
public List<TrivyRegistryCredentialOptions> TrivyRegistryCredentials { get; set; } = [];

with a new options class Configuration/TrivyRegistryCredentialOptions.cs (one type per file) containing Registry (host, e.g. registry.example.com), Username, Password — all XML-documented. Validate in DockerUpdateGuardOptionsValidator.ValidateVulnerabilityOptions: when Trivy is the enabled provider, every credential entry must have all three values non-blank, and Registry values must be unique (case-insensitive) — follow the duplicate-name pattern used in ValidateDockerInstances.

2. Provider changes

  • IProcessRunner.RunAsync currently takes no environment variables — check its signature in Infrastructure/ first. If needed, add an optional IReadOnlyDictionary<string, string>? environmentVariables = null parameter to the interface and thread it through ProcessRunner (ProcessStartInfo.Environment[...]). Update all existing callers/substitutes (compile errors will point at them).
  • In TrivyVulnerabilityProvider.GetVulnerabilitiesAsync, when the image's registry (case-insensitive) matches a configured credential entry, pass TRIVY_USERNAME/TRIVY_PASSWORD for the spawned process. Never log the password; do not put credentials into CLI arguments (they would leak into process lists).
  • When the registry is not docker.io and no credential entry matches, behavior stays as today (Trivy may still succeed for public registries).

3. Documentation

  • Document the new configuration block with an example in DOCKER.md (where the other Vulnerabilities settings are documented) and note the security caveat that credentials come from configuration/environment like the other secrets in this app.
  • Also document the existing limitation that the Trivy server needs network access to the registries it scans.

Testing

  • TrivyVulnerabilityProviderTests: extend the IProcessRunner substitute capture to record the environment dictionary; assert (a) matching registry → TRIVY_USERNAME/TRIVY_PASSWORD set with configured values, (b) non-matching registry → no Trivy credential variables passed, (c) docker.io images → no credential variables passed.
  • DockerUpdateGuardOptionsValidatorTests: incomplete credential entry fails validation with the exact property path in the message; duplicate registries fail; valid setup passes.
  • Follow {Class}{Scenario}{ExpectedResult} naming with assertion messages.

Acceptance criteria

  • Private-registry images scan successfully when credentials are configured (verified by the environment-variable passing tests; a manual end-to-end check against a real private registry is a bonus, not a requirement).
  • Credentials never appear in logs or CLI arguments.
  • Validation rejects incomplete/duplicate credential entries with clear messages.
  • Docs updated. 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