Add component detectors for Docker Compose, Helm, and Kubernetes#1759
Add component detectors for Docker Compose, Helm, and Kubernetes#1759
Conversation
|
👋 Hi! It looks like you modified some files in the
If none of the above scenarios apply, feel free to ignore this comment 🙂 |
There was a problem hiding this comment.
Pull request overview
Adds new YAML-based detectors to Component Detection so Docker image references can be discovered from Docker Compose, Helm values, and Kubernetes manifests, plus updates orchestration wiring and expands detector test coverage.
Changes:
- Introduce new
DockerCompose,Helm, andKubernetesdetectors that parse YAML and registerDockerReferenceComponentusages. - Register the new detectors in Orchestrator DI and extend
DetectorClasswith new categories. - Add MSTest coverage for the new detectors and add/expand tests for the existing Dockerfile detector.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs | Adds unit tests for K8s YAML image extraction and non-K8s YAML ignoring behavior. |
| test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs | Adds unit tests for Helm values.yaml image patterns (scalar, structured, digest, sequences). |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs | Adds Dockerfile detector tests for FROM, multi-stage, digests, COPY --from, and file patterns. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs | Adds tests for Compose service images, overrides, digests, and build-only services. |
| src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs | Registers the three new detectors with DI so they can be executed by the orchestrator. |
| src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs | New detector implementation for parsing Kubernetes manifests and extracting container images. |
| src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs | New detector implementation for parsing Helm values.yaml and extracting image references. |
| src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs | New detector implementation for parsing Compose YAML and extracting service image: references. |
| src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs | Adds new detector classes/categories for Docker Compose, Helm, and Kubernetes. |
Comments suppressed due to low confidence (5)
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs:104
- This file is compiled with nullable reference types enabled, but
apiVersion/kindare declared as non-nullablestringand initialized tonull, which will fail the build with warnings-as-errors. Make thesestring?(and similarly update any other locals/returns that can be null).
private bool IsKubernetesManifest(YamlMappingNode rootMapping)
{
string apiVersion = null;
string kind = null;
foreach (var entry in rootMapping.Children)
{
var key = (entry.Key as YamlScalarNode)?.Value;
if (string.Equals(key, "apiVersion", StringComparison.OrdinalIgnoreCase))
{
apiVersion = (entry.Value as YamlScalarNode)?.Value;
}
else if (string.Equals(key, "kind", StringComparison.OrdinalIgnoreCase))
{
kind = (entry.Value as YamlScalarNode)?.Value;
}
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs:217
GetMappingChildreturnsnullwhen the key isn't present, but the return type is non-nullableYamlMappingNode. With nullable enabled + warnings-as-errors this will fail compilation. Change the return type toYamlMappingNode?(and update call sites accordingly).
private static YamlMappingNode GetMappingChild(YamlMappingNode parent, string key)
{
foreach (var entry in parent.Children)
{
if (entry.Key is YamlScalarNode scalarKey && string.Equals(scalarKey.Value, key, StringComparison.OrdinalIgnoreCase))
{
return entry.Value as YamlMappingNode;
}
}
return null;
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs:230
GetSequenceChildreturnsnullwhen the key isn't present, but the return type is non-nullableYamlSequenceNode. With nullable enabled + warnings-as-errors this will fail compilation. Change the return type toYamlSequenceNode?(and update call sites accordingly).
private static YamlSequenceNode GetSequenceChild(YamlMappingNode parent, string key)
{
foreach (var entry in parent.Children)
{
if (entry.Key is YamlScalarNode scalarKey && string.Equals(scalarKey.Value, key, StringComparison.OrdinalIgnoreCase))
{
return entry.Value as YamlSequenceNode;
}
}
return null;
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs:135
- This method initializes non-nullable
stringlocals (repository,tag,digest,registry) tonull. With nullable enabled + TreatWarningsAsErrors, this will fail the build. Usestring?for these locals (and keep the subsequent null/whitespace checks).
private void TryRegisterStructuredImageReference(YamlMappingNode imageMapping, ISingleFileComponentRecorder recorder, string fileLocation)
{
string repository = null;
string tag = null;
string digest = null;
string registry = null;
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs:137
GetMappingChildreturnsnullwhen the key isn't present, but the return type is non-nullableYamlMappingNode. With nullable enabled + warnings-as-errors this will fail compilation. Change the return type toYamlMappingNode?and update call sites accordingly.
private static YamlMappingNode GetMappingChild(YamlMappingNode parent, string key)
{
foreach (var entry in parent.Children)
{
if (entry.Key is YamlScalarNode scalarKey && string.Equals(scalarKey.Value, key, StringComparison.OrdinalIgnoreCase))
{
return entry.Value as YamlMappingNode;
}
}
return null;
|
|
||
| public override int Version => 1; | ||
|
|
||
| public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Kubernetes)]; |
There was a problem hiding this comment.
Enum.GetName(...) returns string? under nullable reference types. Returning it directly here can fail compilation (and can propagate null into Categories). Use the null-forgiving operator (!) or an alternate non-null approach (e.g., nameof(DetectorClass.Kubernetes)).
This issue also appears in the following locations of the same file:
- line 88
- line 206
- line 219
| public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Kubernetes)]; | |
| public override IEnumerable<string> Categories => [nameof(DetectorClass.Kubernetes)]; |
|
|
||
| public override int Version => 1; | ||
|
|
||
| public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Helm)]; |
There was a problem hiding this comment.
Enum.GetName(...) returns string? under nullable reference types. Returning it directly here can fail compilation and can propagate null into Categories. Use ! (as some other detectors do) or another guaranteed-non-null approach (e.g., nameof(DetectorClass.Helm)).
This issue also appears on line 129 of the same file.
| public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Helm)]; | |
| public override IEnumerable<string> Categories => [nameof(DetectorClass.Helm)]; |
|
|
||
| public override IEnumerable<ComponentType> SupportedComponentTypes => [ComponentType.DockerReference]; | ||
|
|
||
| public override int Version => 1; | ||
|
|
||
| public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.DockerCompose)]; |
There was a problem hiding this comment.
Enum.GetName(...) returns string? under nullable reference types. Returning it directly here can fail compilation and can propagate null into Categories. Use the null-forgiving operator (!) or an alternate non-null approach.
This issue also appears on line 126 of the same file.
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs
Show resolved
Hide resolved
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs
Show resolved
Hide resolved
| this.Logger.LogInformation("Discovered Helm file: {Location}", file.Location); | ||
|
|
||
| string contents; | ||
| using (var reader = new StreamReader(file.Stream)) | ||
| { | ||
| contents = await reader.ReadToEndAsync(cancellationToken); | ||
| } | ||
|
|
||
| var yaml = new YamlStream(); | ||
| yaml.Load(new StringReader(contents)); | ||
|
|
||
| if (yaml.Documents.Count == 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var fileName = Path.GetFileName(file.Location); | ||
|
|
||
| if (fileName.Contains("values", StringComparison.OrdinalIgnoreCase) && | ||
| (fileName.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".yml", StringComparison.OrdinalIgnoreCase))) | ||
| { | ||
| this.ExtractImageReferencesFromValues(yaml, singleFileComponentRecorder, file.Location); | ||
| } |
There was a problem hiding this comment.
This method parses YAML for every matched file (including Chart.yaml/Chart.yml) even though only *values*.(yml|yaml) files are actually processed for image extraction. Since the filename decision is based solely on file.Location, you can short-circuit before reading/parsing the stream for non-values files to avoid unnecessary work and noise in logs.
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs
Show resolved
Hide resolved
…d improve logging
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs:86
- The exception handler logs "Skipping non-Kubernetes YAML file" for any exception, but exceptions here primarily represent YAML parse/processing failures (a file can be a Kubernetes manifest but malformed). Consider adjusting the message to reflect parse errors (or splitting try/catch so non-Kubernetes vs parse-failure are distinguished) to avoid misleading diagnostics.
catch (Exception e)
{
// Not all YAML files are Kubernetes manifests; silently skip parse errors
this.Logger.LogDebug(e, "Skipping non-Kubernetes YAML file: {Location}", file.Location);
}
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs
Show resolved
Hide resolved
…prove error logging. And address SA1204
| private void TryRegisterImageReference(string imageReference, ISingleFileComponentRecorder recorder, string fileLocation) | ||
| { | ||
| try | ||
| { | ||
| var dockerRef = DockerReferenceUtility.ParseFamiliarName(imageReference); | ||
| if (dockerRef != null) | ||
| { | ||
| recorder.RegisterUsage(new DetectedComponent(dockerRef.ToTypedDockerReferenceComponent())); | ||
| } | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| this.Logger.LogWarning(e, "Failed to parse image reference '{ImageReference}' in {Location}", imageReference, fileLocation); | ||
| } |
There was a problem hiding this comment.
Docker Compose files commonly use variable interpolation in image (e.g., ${REGISTRY}/app:${TAG}). DockerReferenceUtility.ParseFamiliarName throws on these, which will generate warnings for otherwise valid compose files. Consider skipping registration when the image reference contains unresolved variables (similar to DockerfileComponentDetector.HasUnresolvedVariables) instead of logging a warning for each occurrence.
| private void TryRegisterImageReference(string imageReference, ISingleFileComponentRecorder recorder, string fileLocation) | ||
| { | ||
| try | ||
| { | ||
| var dockerRef = DockerReferenceUtility.ParseFamiliarName(imageReference); | ||
| if (dockerRef != null) | ||
| { | ||
| recorder.RegisterUsage(new DetectedComponent(dockerRef.ToTypedDockerReferenceComponent())); | ||
| } | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| this.Logger.LogWarning(e, "Failed to parse image reference '{ImageReference}' in {Location}", imageReference, fileLocation); | ||
| } |
There was a problem hiding this comment.
Helm values often use templated/variable image strings (e.g., ${REGISTRY} or {{ .Values.image.tag }} via preprocessing). Passing these through DockerReferenceUtility.ParseFamiliarName will throw and can create noisy warning logs. Consider detecting unresolved variables/templates in imageReference and skipping registration (without logging) to match the Dockerfile detector’s behavior.
| private void TryRegisterImageReference(string imageReference, ISingleFileComponentRecorder recorder, string fileLocation) | ||
| { | ||
| try | ||
| { | ||
| var dockerRef = DockerReferenceUtility.ParseFamiliarName(imageReference); | ||
| if (dockerRef != null) | ||
| { | ||
| recorder.RegisterUsage(new DetectedComponent(dockerRef.ToTypedDockerReferenceComponent())); | ||
| } | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| this.Logger.LogWarning(e, "Failed to parse image reference '{ImageReference}' in {Location}", imageReference, fileLocation); | ||
| } |
There was a problem hiding this comment.
Kubernetes manifests frequently use variable placeholders in image: (e.g., ${IMAGE}) via kustomize/CI substitution. DockerReferenceUtility.ParseFamiliarName throws on these, so this will log warnings for many real-world manifests. Consider skipping image references containing unresolved variables/templates (rather than logging) before calling ParseFamiliarName, consistent with DockerfileComponentDetector.HasUnresolvedVariables.
…in a subdirectory of where the chart yaml file was found
There was a problem hiding this comment.
Pull request overview
This PR adds several new DefaultOff detectors to discover and register Docker image references from container-related configuration files (Docker Compose, Helm values, Kubernetes manifests) and centralizes “skip unresolved variables” logic in a shared Docker reference utility.
Changes:
- Added new detectors:
DockerComposeComponentDetector,HelmComponentDetector, andKubernetesComponentDetector, plus DI registration. - Added/updated shared Docker reference parsing helpers to silently skip image references containing unresolved variable placeholders.
- Added detector docs and a suite of unit tests for the new detectors (and Dockerfile).
Show a summary per file
| File | Description |
|---|---|
| src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs | New detector to parse Compose YAML and register image references. |
| src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs | New detector to parse Helm values YAML (with chart co-location filtering) and register image references. |
| src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs | New detector to parse Kubernetes YAML workload manifests and register container image references. |
| src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs | Added shared “unresolved variable” detection and safe parse/register helpers. |
| src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs | Updated to use the shared Docker reference utility parsing logic. |
| src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs | Registered the new detectors in DI. |
| src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs | Added new detector classes for DockerCompose/Helm/Kubernetes. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs | Added tests for Compose image extraction behaviors. |
| test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs | Added tests for Helm values parsing/co-location behaviors. |
| test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs | Added tests for Kubernetes manifest image extraction behaviors. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs | Added tests validating Dockerfile image extraction and variable skipping. |
| docs/detectors/dockercompose.md | Added detector documentation. |
| docs/detectors/helm.md | Added detector documentation. |
| docs/detectors/kubernetes.md | Added detector documentation. |
| docs/detectors/README.md | Linked the new detector docs in the detector index. |
| .gitignore | Ignored .nuget/. |
Copilot's findings
- Files reviewed: 15/16 changed files
- Comments generated: 3
| ### Supported Resource Kinds | ||
|
|
||
| The detector recognizes the following Kubernetes resource kinds: | ||
|
|
||
| - `Pod` | ||
| - `Deployment` | ||
| - `StatefulSet` | ||
| - `DaemonSet` | ||
| - `ReplicaSet` | ||
| - `Job` | ||
| - `CronJob` | ||
| - `ReplicationController` | ||
|
|
There was a problem hiding this comment.
The doc’s “Supported Resource Kinds” list doesn’t include PodTemplate, but the implementation’s KubernetesKinds set does. Please update the documentation to reflect the actual supported kinds (or remove PodTemplate support if it’s not intended).
| [TestMethod] | ||
| public async Task TestCompose_OverrideFileAsync() | ||
| { | ||
| var composeYaml = @" | ||
| services: | ||
| web: | ||
| image: myregistry.io/web:latest | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("docker-compose.override.yml", composeYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
There was a problem hiding this comment.
These tests appear to validate that override/env-specific filenames (e.g., docker-compose.override.yml, compose.prod.yaml) are discovered via SearchPatterns, but DetectorTestUtilityBuilder injects provided files into the detector even when they don’t match the detector’s patterns (it only affects ComponentStream.Pattern). Consider adding a unit test for PathUtilityService.MatchesPattern/pattern matching with these patterns, or enhancing the test utility to only emit files that actually match SearchPatterns, so file-discovery behavior is covered.
| public async Task TestHelm_ValuesOverrideFileAsync() | ||
| { | ||
| var valuesYaml = @" | ||
| image: redis:7-alpine | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("Chart.yaml", MinimalChartYaml) | ||
| .WithFile("values.production.yaml", valuesYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
||
| scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
| componentRecorder.GetDetectedComponents().Should().ContainSingle(); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public async Task TestHelm_CustomValuesFilenameAsync() | ||
| { | ||
| var valuesYaml = @" | ||
| image: postgres:15 | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("Chart.yaml", MinimalChartYaml) | ||
| .WithFile("myapp-values-dev.yml", valuesYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
||
| scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
| componentRecorder.GetDetectedComponents().Should().ContainSingle(); | ||
| } |
There was a problem hiding this comment.
Several tests here use filenames like values.production.yaml / myapp-values-dev.yml to validate Helm file discovery, but DetectorTestUtilityBuilder will execute the detector for any provided file regardless of whether it matches SearchPatterns (pattern matching only influences ComponentStream.Pattern). Consider adding explicit pattern-matching tests (or updating the test utility to filter by SearchPatterns) so the intended file-discovery behavior is actually covered.
There was a problem hiding this comment.
Pull request overview
Adds new DefaultOff detectors to discover Docker image references in Docker Compose, Helm values, and Kubernetes manifests, and centralizes Docker image variable-placeholder skipping across Docker-related detectors.
Changes:
- Introduces
DockerComposeComponentDetector,HelmComponentDetector, andKubernetesComponentDetector(plus DI registration andDetectorClassupdates). - Adds
DockerReferenceUtility.HasUnresolvedVariables/TryParseImageReference/TryRegisterImageReferenceand updates Dockerfile detector to use the shared logic. - Adds detector documentation pages and comprehensive unit tests for the new detectors (and Dockerfile).
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs | Adds unit tests for Kubernetes image extraction and variable-skipping behavior. |
| test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs | Adds unit tests for Helm values parsing, chart co-location behavior, and digests. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs | Adds unit tests covering Dockerfile image extraction, digests, and unresolved variables. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs | Adds unit tests for Docker Compose image extraction and common filename variants. |
| src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs | Registers the new detectors in the orchestrator DI container. |
| src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs | New Kubernetes detector parsing YAML manifests to extract container image references. |
| src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs | New Helm detector scanning values files and enforcing Chart co-location. |
| src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs | Updates existing Dockerfile detector to use shared Docker reference parsing/skip logic. |
| src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs | New Docker Compose detector scanning service image: fields. |
| src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs | Adds DockerCompose, Helm, and Kubernetes detector classes. |
| src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs | Adds shared helpers to detect unresolved variables and safely parse/register image references. |
| docs/detectors/README.md | Links to new detector documentation pages. |
| docs/detectors/kubernetes.md | Documents Kubernetes detector requirements/strategy/limitations. |
| docs/detectors/helm.md | Documents Helm detector requirements/strategy/limitations. |
| docs/detectors/dockercompose.md | Documents Docker Compose detector requirements/strategy/limitations. |
| .gitignore | Ignores .nuget/ directory. |
Copilot's findings
- Files reviewed: 15/16 changed files
- Comments generated: 3
| /// <summary> | ||
| /// Fast text-based pre-filter. Checks for "apiVersion" and a known "kind: <K8sKind>" | ||
| /// pattern using span operations to reject non-Kubernetes YAML without YAML parsing. | ||
| /// </summary> | ||
| private static bool LooksLikeKubernetesManifest(string contents) | ||
| { | ||
| var span = contents.AsSpan(); | ||
|
|
||
| // Must contain apiVersion to be any kind of K8s manifest. | ||
| if (span.IndexOf("apiVersion".AsSpan(), StringComparison.Ordinal) < 0) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // Check for a known "kind: <K8sResource>" pattern. This is much more specific | ||
| // than just checking for "kind" and eliminates non-K8s YAML files (GitHub Actions, | ||
| // Azure Pipelines, CloudFormation, etc.) that also contain generic "kind" keys. | ||
| foreach (var pattern in KubernetesKindPatterns) | ||
| { | ||
| if (span.IndexOf(pattern.AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } |
There was a problem hiding this comment.
The LooksLikeKubernetesManifest fast-path only looks for exact substrings like kind: Deployment. Valid manifests that quote the value (e.g., kind: "Deployment") won’t match any pattern and will be skipped before YAML parsing, causing missed detections. Consider loosening the prefilter (e.g., detect kind: plus any known kind token, allow optional quotes/whitespace, or fall back to YAML parsing when apiVersion is present).
| - **DefaultOff Status**: This detector must be explicitly enabled using `--DetectorArgs Kubernetes=EnableIfDefaultOff` | ||
| - **Broad File Matching**: The `*.yaml` and `*.yml` search patterns match all YAML files, so the detector relies on content-based filtering (`apiVersion` and `kind` fields) to identify Kubernetes manifests | ||
| - **Variable Resolution**: Image references containing unresolved template variables are not reported | ||
| - **Limited Resource Kinds**: Only the eight resource kinds listed above are supported. Custom resources (CRDs) or other workload types are not detected |
There was a problem hiding this comment.
The limitations section says “Only the eight resource kinds listed above are supported”, but the document lists nine kinds (Pod, PodTemplate, Deployment, StatefulSet, DaemonSet, ReplicaSet, Job, CronJob, ReplicationController). Please update the count to avoid confusion.
| - **Limited Resource Kinds**: Only the eight resource kinds listed above are supported. Custom resources (CRDs) or other workload types are not detected | |
| - **Limited Resource Kinds**: Only the nine resource kinds listed above are supported. Custom resources (CRDs) or other workload types are not detected |
| [TestMethod] | ||
| public async Task TestCompose_OverrideFileAsync() | ||
| { | ||
| var composeYaml = @" | ||
| services: | ||
| web: | ||
| image: myregistry.io/web:latest | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("docker-compose.override.yml", composeYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
||
| scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
| var components = componentRecorder.GetDetectedComponents(); | ||
| components.Should().ContainSingle(); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public async Task TestCompose_UnresolvedVariableSkippedAsync() | ||
| { | ||
| var composeYaml = @" | ||
| services: | ||
| app: | ||
| image: ${REGISTRY}/app:${TAG} | ||
| db: | ||
| image: postgres:15 | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("docker-compose.yml", composeYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
||
| scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
| var components = componentRecorder.GetDetectedComponents(); | ||
|
|
||
| // Only the literal image reference (postgres:15) should be registered; | ||
| // the variable-interpolated image (${REGISTRY}/app:${TAG}) should be silently skipped. | ||
| components.Should().ContainSingle(); | ||
| var dockerRef = components.First().Component as DockerReferenceComponent; | ||
| dockerRef.Should().NotBeNull(); | ||
| dockerRef.Repository.Should().Be("library/postgres"); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public async Task TestCompose_ComposeOverrideFileAsync() | ||
| { | ||
| var composeYaml = @" | ||
| services: | ||
| web: | ||
| image: nginx:1.21 | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("compose.override.yml", composeYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
||
| scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
| componentRecorder.GetDetectedComponents().Should().ContainSingle(); | ||
| } | ||
|
|
||
| [TestMethod] | ||
| public async Task TestCompose_ComposeOverrideYamlAsync() | ||
| { | ||
| var composeYaml = @" | ||
| services: | ||
| db: | ||
| image: postgres:15 | ||
| "; | ||
|
|
||
| var (scanResult, componentRecorder) = await this.DetectorTestUtility | ||
| .WithFile("compose.prod.yaml", composeYaml) | ||
| .ExecuteDetectorAsync(); | ||
|
|
||
| scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
| componentRecorder.GetDetectedComponents().Should().ContainSingle(); | ||
| } |
There was a problem hiding this comment.
The override/variant filename tests here can give a false sense of coverage for real file discovery. DetectorTestUtilityBuilder supplies the file to the detector even if it wouldn’t match SearchPatterns during a real scan, so these tests won’t fail if the wildcard patterns are unsupported by PathUtilityService.MatchesPattern. Consider adding an assertion that the filename matches one of the detector’s SearchPatterns (using the same matcher the walker uses) to ensure these variants are actually discoverable.
There was a problem hiding this comment.
Pull request overview
This pull request adds new DefaultOff detectors to discover and register Docker image references from Docker Compose, Helm values, and Kubernetes YAML manifests, and centralizes “unresolved variable” skipping logic in a shared Docker reference utility.
Changes:
- Added new detectors:
DockerComposeComponentDetector,HelmComponentDetector, andKubernetesComponentDetector, plus DI registration andDetectorClassenum updates. - Added/updated Docker image parsing utilities (
DockerReferenceUtility) and updated the existing Dockerfile detector to reuse shared parsing/skip logic. - Added unit tests and verification-test resources/workflow updates for the new detectors.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 | Enables new detectors in verification scan script. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/statefulset.yaml | Adds Kubernetes sample manifest for verification resources. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/deployment.yaml | Adds Kubernetes sample manifest for verification resources. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/cronjob.yaml | Adds Kubernetes sample manifest for verification resources. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/helm/values.yaml | Adds Helm values sample for verification resources. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/helm/Chart.yaml | Adds Helm chart metadata sample for verification resources. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/dockercompose/docker-compose.yml | Adds Docker Compose sample for verification resources. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/dockercompose/docker-compose.override.yml | Adds Docker Compose override sample for verification resources. |
| test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs | Adds unit tests for Kubernetes image extraction and skipping unresolved variables. |
| test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs | Adds unit tests for Helm values parsing and chart co-location behavior. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs | Adds/updates unit tests for Dockerfile detector behavior including unresolved variable skipping. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs | Adds unit tests for Docker Compose parsing and unresolved variable skipping. |
| src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs | Registers the new detectors in DI. |
| src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs | Implements Kubernetes YAML detection/parsing and image extraction. |
| src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs | Implements Helm detection with chart/values co-location gating and YAML traversal. |
| src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs | Refactors Dockerfile parsing to use shared Docker reference utility methods. |
| src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs | Implements Docker Compose YAML detection/parsing and image extraction. |
| src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs | Adds DockerCompose, Helm, and Kubernetes detector classes. |
| src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs | Adds shared helpers for unresolved-variable detection and “try-parse/register” behavior. |
| docs/detectors/README.md | Links to new detector documentation pages and adds status entries. |
| docs/detectors/kubernetes.md | Adds documentation for Kubernetes detector behavior/limitations. |
| docs/detectors/helm.md | Adds documentation for Helm detector behavior/limitations. |
| docs/detectors/dockercompose.md | Adds documentation for Docker Compose detector behavior/limitations. |
| .gitignore | Ignores local .nuget/ directory. |
| .github/workflows/snapshot-verify.yml | Enables new detectors during snapshot verification scan. |
| .github/workflows/snapshot-publish.yml | Enables new detectors during snapshot publish scan. |
Copilot's findings
- Files reviewed: 25/26 changed files
- Comments generated: 2
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs
Show resolved
Hide resolved
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
This PR extends Component Detection’s Docker image reference scanning by adding DefaultOff detectors for Docker Compose, Helm values, and Kubernetes manifests, plus consolidating “unresolved variable” skipping into a shared utility used across Docker-related detectors.
Changes:
- Added new detectors:
DockerComposeComponentDetector,HelmComponentDetector,KubernetesComponentDetectorand registered them in DI. - Added shared Docker reference helpers (
HasUnresolvedVariables,TryParseImageReference,TryRegisterImageReference) and updated the Dockerfile detector to use them. - Added unit tests + verification resources/docs and enabled the new detectors in snapshot/verification workflows.
Show a summary per file
| File | Description |
|---|---|
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs |
New Docker Compose YAML detector for services.*.image references. |
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs |
New Helm detector with Chart/values co-location logic and YAML walk for image keys. |
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs |
New Kubernetes detector that parses YAML documents to extract container image references. |
src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs |
Adds shared parsing/registration helpers and unresolved-variable skipping. |
src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs |
Refactors to use DockerReferenceUtility.TryParseImageReference (removes local regex check). |
src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs |
Registers the new detectors in DI. |
src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs |
Adds DockerCompose, Helm, Kubernetes detector classes. |
test/Microsoft.ComponentDetection.Detectors.Tests/* |
Adds tests for new detectors and expands Dockerfile detector tests. |
test/Microsoft.ComponentDetection.VerificationTests/resources/* |
Adds verification resources for docker-compose/helm/kubernetes detectors. |
docs/detectors/* |
Adds detector documentation pages and links from detectors README. |
.github/workflows/snapshot-verify.yml / .github/workflows/snapshot-publish.yml |
Enables the new DefaultOff detectors for snapshot scans. |
test/.../VerificationTest.ps1 |
Enables the new DefaultOff detectors in the local verification script. |
.gitignore |
Ignores .nuget/. |
Copilot's findings
Comments suppressed due to low confidence (4)
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs:39
SearchPatternsuses*values*.*(wildcard in the middle), but the repo’s filename matcher (PathUtilityService.MatchesPattern) only supports*as a leading or trailing wildcard. As a result, values files likevalues.production.yaml/myapp-values-dev.ymlwon’t be discovered in real scans, so the detector will effectively never run. Consider switching to patterns the matcher supports (e.g.,*.yaml/*.yml) and rely onIsValuesFile+ the Chart co-location filtering inOnPrepareDetectionAsync.
public override IList<string> SearchPatterns { get; } =
[
"Chart.yaml", "Chart.yml",
"*values*.yaml", "*values*.yml",
];
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs:36
SearchPatternsincludesdocker-compose.*.yml/compose.*.yaml(wildcard in the middle), but the repo’s filename matcher only supports*at the start or end. These patterns will be treated literally, so override/env-specific compose files (e.g.,docker-compose.override.yml,compose.prod.yaml) won’t be discovered in production scans. Please change to supported prefix patterns (e.g.,docker-compose.*/compose.*) or broaden to*.yml/*.yamlwith a filename/content filter.
public override IList<string> SearchPatterns { get; } =
[
"docker-compose.yml", "docker-compose.yaml",
"docker-compose.*.yml", "docker-compose.*.yaml",
"compose.yml", "compose.yaml",
"compose.*.yml", "compose.*.yaml",
];
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs:166
LooksLikeKubernetesManifestis likely to produce false negatives because it only returns true when the file contains an exact substring likekind: Deployment(no quotes, no additional whitespace). Valid manifests such askind: "Deployment"orkind: Deploymentwill be skipped without YAML parsing, and their images won’t be detected. Consider making the prefilter tolerant of whitespace/quotes (or just check forapiVersion+kind:and letIsKubernetesManifestdo the precise validation).
// Must contain apiVersion to be any kind of K8s manifest.
if (span.IndexOf("apiVersion".AsSpan(), StringComparison.Ordinal) < 0)
{
return false;
}
// Check for a known "kind: <K8sResource>" pattern. This is much more specific
// than just checking for "kind" and eliminates non-K8s YAML files (GitHub Actions,
// Azure Pipelines, CloudFormation, etc.) that also contain generic "kind" keys.
foreach (var pattern in KubernetesKindPatterns)
{
if (span.IndexOf(pattern.AsSpan(), StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs:153
- The
apiVersionprefilter uses a case-sensitiveIndexOf(..., StringComparison.Ordinal). Even thoughapiVersionis normally cased this way, usingOrdinalIgnoreCasewould be more robust and consistent with the rest of the detector’s case-insensitive checks, without materially impacting performance.
// Must contain apiVersion to be any kind of K8s manifest.
if (span.IndexOf("apiVersion".AsSpan(), StringComparison.Ordinal) < 0)
{
return false;
}
- Files reviewed: 25/26 changed files
- Comments generated: 4
| using Microsoft.ComponentDetection.Common; | ||
| using Microsoft.ComponentDetection.Contracts; | ||
| using Microsoft.ComponentDetection.Contracts.Internal; | ||
| using Microsoft.ComponentDetection.Contracts.TypedComponent; |
There was a problem hiding this comment.
There’s an unused using Microsoft.ComponentDetection.Contracts.TypedComponent; here. With TreatWarningsAsErrors=true, this is likely to fail the build with CS8019. Please remove the unused using (or reference a type from that namespace if it’s actually needed).
This issue also appears on line 35 of the same file.
| using Microsoft.ComponentDetection.Contracts.TypedComponent; |
| using Microsoft.ComponentDetection.Common; | ||
| using Microsoft.ComponentDetection.Contracts; | ||
| using Microsoft.ComponentDetection.Contracts.Internal; | ||
| using Microsoft.ComponentDetection.Contracts.TypedComponent; |
There was a problem hiding this comment.
There’s an unused using Microsoft.ComponentDetection.Contracts.TypedComponent; here. With TreatWarningsAsErrors=true, this can fail the build (CS8019). Please remove the unused using.
This issue also appears on line 30 of the same file.
| using Microsoft.ComponentDetection.Contracts.TypedComponent; |
| using Microsoft.ComponentDetection.Common; | ||
| using Microsoft.ComponentDetection.Contracts; | ||
| using Microsoft.ComponentDetection.Contracts.Internal; | ||
| using Microsoft.ComponentDetection.Contracts.TypedComponent; |
There was a problem hiding this comment.
There’s an unused using Microsoft.ComponentDetection.Contracts.TypedComponent; here. With TreatWarningsAsErrors=true, this can fail the build (CS8019). Please remove the unused using.
This issue also appears in the following locations of the same file:
- line 148
- line 148
| using Microsoft.ComponentDetection.Contracts.TypedComponent; |
| Docker Compose detection depends on the following to successfully run: | ||
|
|
||
| - One or more Docker Compose files matching the patterns: `docker-compose.yml`, `docker-compose.yaml`, `docker-compose.*.yml`, `docker-compose.*.yaml`, `compose.yml`, `compose.yaml`, `compose.*.yml`, `compose.*.yaml` | ||
|
|
There was a problem hiding this comment.
The documented patterns include docker-compose.*.yml / compose.*.yaml, but the repo’s file discovery matcher only supports * as a leading or trailing wildcard. These mid-string wildcard patterns won’t match in production, so the docs currently promise support that won’t work. Please update the documented patterns to the supported form (or update the detector + matcher and keep docs in sync).
There was a problem hiding this comment.
Pull request overview
Adds new DefaultOff detectors to discover Docker image references in common YAML-based deployment formats (Docker Compose, Helm values, and Kubernetes manifests), and unifies “skip unresolved variable placeholders” behavior across Docker-related detectors via shared parsing helpers in DockerReferenceUtility.
Changes:
- Introduces
DockerComposeComponentDetector,HelmComponentDetector, andKubernetesComponentDetector, plus DI + docs wiring. - Adds shared
DockerReferenceUtility.HasUnresolvedVariables/TryParseImageReference/TryRegisterImageReferenceand updatesDockerfileComponentDetectorto use them. - Expands unit tests and verification resources/workflows to cover the new detectors.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 | Enables new DefaultOff detectors in local verification script. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/statefulset.yaml | Adds Kubernetes verification resource with image refs. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/deployment.yaml | Adds Kubernetes verification resource with multiple image ref forms (tag/digest). |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/cronjob.yaml | Adds Kubernetes verification resource for CronJob image refs. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/helm/values.yaml | Adds Helm values verification resource with multiple image patterns. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/helm/Chart.yaml | Adds Helm chart marker file for co-location logic. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/dockercompose/docker-compose.yml | Adds Docker Compose verification resource with images. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/dockercompose/docker-compose.override.yml | Adds Docker Compose override verification resource. |
| test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs | Adds unit tests for Kubernetes YAML image extraction and skipping unresolved variables. |
| test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs | Adds unit tests for Helm values parsing + chart co-location ordering. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs | Adds unit tests for Dockerfile parsing, including unresolved variable skipping. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs | Adds unit tests for Docker Compose parsing + unresolved variable skipping. |
| src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs | Registers new detectors in DI. |
| src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs | Implements Kubernetes YAML detector with prefilter + YAML parsing and image extraction. |
| src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs | Implements Helm values detector with two-pass chart-directory discovery. |
| src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs | Refactors Dockerfile detector to use shared Docker reference parsing/skip logic. |
| src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs | Implements Docker Compose YAML detector for service image fields. |
| src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs | Adds new detector categories: DockerCompose, Helm, Kubernetes. |
| src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs | Adds shared unresolved-variable detection + safe parsing/registration helpers. |
| docs/detectors/README.md | Links new detector docs pages. |
| docs/detectors/kubernetes.md | Adds documentation for Kubernetes detector behavior/limitations. |
| docs/detectors/helm.md | Adds documentation for Helm detector behavior/limitations. |
| docs/detectors/dockercompose.md | Adds documentation for Docker Compose detector behavior/limitations. |
| .gitignore | Ignores .nuget/ directory. |
| .github/workflows/snapshot-verify.yml | Enables new detectors in verification workflow. |
| .github/workflows/snapshot-publish.yml | Enables new detectors in publish workflow. |
Copilot's findings
- Files reviewed: 25/26 changed files
- Comments generated: 1
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Adds new DefaultOff detectors to Component Detection for discovering Docker image references in Docker Compose, Helm values, and Kubernetes manifests, and standardizes Docker image parsing/skip behavior across Docker-related detectors.
Changes:
- Introduces
DockerComposeComponentDetector,HelmComponentDetector, andKubernetesComponentDetector, registers them in DI, and adds newDetectorClassentries. - Adds shared
DockerReferenceUtilityhelpers to silently skip image references containing unresolved variables, and updates the existing Dockerfile detector to use the shared parsing. - Expands unit tests, verification resources, docs, and CI/verification scripts to cover the new detectors.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 | Enables the new DefaultOff detectors during local verification runs. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/statefulset.yaml | Adds Kubernetes manifest fixture containing an image reference. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/deployment.yaml | Adds Kubernetes manifest fixture with multiple image forms (tag, digest). |
| test/Microsoft.ComponentDetection.VerificationTests/resources/kubernetes/cronjob.yaml | Adds Kubernetes manifest fixture for CronJob image extraction. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/helm/values.yaml | Adds Helm values fixture covering multiple image declaration patterns. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/helm/Chart.yaml | Adds Helm chart marker fixture to validate co-location logic. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/dockercompose/docker-compose.yml | Adds Docker Compose fixture with multiple services/images. |
| test/Microsoft.ComponentDetection.VerificationTests/resources/dockercompose/docker-compose.override.yml | Adds Docker Compose override fixture for variant compose filenames. |
| test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs | Adds unit tests covering Kubernetes image extraction and skip behavior. |
| test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs | Adds unit tests for Helm values parsing and chart co-location filtering. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs | Adds/updates tests for Dockerfile parsing and unresolved variable skipping. |
| test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs | Adds unit tests for Docker Compose parsing and skip behavior. |
| src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs | Registers the new detectors in the orchestrator DI container. |
| src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs | Implements Kubernetes YAML parsing + fast pre-filtering and image extraction. |
| src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs | Implements Helm values parsing with two-pass chart directory detection. |
| src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs | Switches Dockerfile parsing to shared Docker reference parsing/skip helper. |
| src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs | Implements Docker Compose YAML parsing for service image references. |
| src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs | Adds detector categories for DockerCompose/Helm/Kubernetes. |
| src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs | Adds shared unresolved-variable detection and safe parse/register helpers. |
| docs/detectors/README.md | Documents the new detectors in the detectors index. |
| docs/detectors/kubernetes.md | Adds Kubernetes detector documentation (requirements/strategy/limitations). |
| docs/detectors/helm.md | Adds Helm detector documentation (requirements/strategy/limitations). |
| docs/detectors/dockercompose.md | Adds Docker Compose detector documentation (requirements/strategy/limitations). |
| .gitignore | Ignores .nuget/ directory. |
| .github/workflows/snapshot-verify.yml | Enables new detectors in CI verification scan. |
| .github/workflows/snapshot-publish.yml | Enables new detectors in CI publish scan. |
Copilot's findings
- Files reviewed: 25/26 changed files
- Comments generated: 3
| private void ExtractImageReferences(YamlMappingNode rootMapping, ISingleFileComponentRecorder recorder, string fileLocation) | ||
| { |
There was a problem hiding this comment.
fileLocation is passed into ExtractImageReferences but never used. Consider removing this parameter (and the corresponding argument at the call site) or using it (e.g., for logging/telemetry) to avoid dead parameters and keep the helper signature minimal.
| } | ||
| } | ||
|
|
||
| private void TryRegisterStructuredImageReference(YamlMappingNode imageMapping, ISingleFileComponentRecorder recorder, string fileLocation) | ||
| { |
There was a problem hiding this comment.
fileLocation is threaded through ExtractImageReferencesFromValues/WalkYamlForImages/TryRegisterStructuredImageReference, but it isn't referenced anywhere in the implementation. Consider removing the parameter from these helper methods (and updating call sites), or use it for logging so it has a purpose.
| } | ||
|
|
||
| private void ExtractImageReferences(YamlMappingNode rootMapping, ISingleFileComponentRecorder recorder, string fileLocation) | ||
| { |
There was a problem hiding this comment.
fileLocation is passed through ExtractImageReferences -> ExtractContainerImages -> ExtractImagesFromContainerList, but it's never used. Consider removing it from these helper method signatures (and call sites) to reduce noise, or use it for logging when registering/skipping images.
| { | |
| { | |
| ArgumentException.ThrowIfNullOrWhiteSpace(fileLocation); |
This pull request adds new detectors for Docker Compose, Helm, and Kubernetes YAML files, enabling the system to automatically discover and register Docker image references found in these types of configuration files. It also updates the service registration and the
DetectorClassenum to support these new detectors.It also adds tests for the new detectors plus the Dockerfile one.
Image references containing unresolved variable placeholders (e.g.,
${REGISTRY}/app:${TAG},{{ .Values.image.tag }}) are silently skipped in all four Docker-related detectors (DockerCompose, Helm, Kubernetes, and Dockerfile) to avoid noisy warnings for otherwise-valid real-world manifests. A sharedDockerReferenceUtility.HasUnresolvedVariableshelper was added toMicrosoft.ComponentDetection.Commonto consolidate this logic, and all detectors—including the existingDockerfileComponentDetector—now use it.The Helm detector uses the combination of a
Chart.yaml/Chart.ymlfile and a*values*.(yaml|yml)file in the same directory to identify Helm charts. Values files found without a co-located Chart file are skipped, avoiding false positives from unrelatedvalues.yamlfiles in non-Helm projects. The co-location check is implemented via a two-passOnPrepareDetectionAsync: all matching files are materialized first, chart directories are identified in pass 1, then only values files from those directories are emitted for processing in pass 2. This eliminates any dependency on file enumeration order, so values files are correctly detected regardless of whether they are observed before or after their co-locatedChart.yaml.A bug in
DetectorRestrictionServicewas also fixed: when bothAllowedDetectorIdsandAllowedDetectorCategoriesare specified, DefaultOff detectors introduced via category expansion are now also constrained by the ID allow-list, producing an intersection rather than an unintended union.New Detector Checklist
ComponentType.csandDetectorClass.csComponent class created inTypedComponent/folder with proper validationFileComponentDetectorand implementingIDefaultOffComponentDetectorServiceCollectionExtensions.csSearchPatternsdefined for file discoveryOnFileFoundAsync()implemented with component registration logicDetectors.Tests/usingDetectorTestUtilityBuilderVerificationTests/resources/--DetectorArgs YourDetectorId=EnableIfDefaultOff