Skip to content

Add component detectors for Docker Compose, Helm, and Kubernetes#1759

Open
jpinz wants to merge 25 commits intomainfrom
jupinzer/add_container_detectors
Open

Add component detectors for Docker Compose, Helm, and Kubernetes#1759
jpinz wants to merge 25 commits intomainfrom
jupinzer/add_container_detectors

Conversation

@jpinz
Copy link
Copy Markdown
Member

@jpinz jpinz commented Apr 2, 2026

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 DetectorClass enum 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 shared DockerReferenceUtility.HasUnresolvedVariables helper was added to Microsoft.ComponentDetection.Common to consolidate this logic, and all detectors—including the existing DockerfileComponentDetector—now use it.

The Helm detector uses the combination of a Chart.yaml/Chart.yml file 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 unrelated values.yaml files in non-Helm projects. The co-location check is implemented via a two-pass OnPrepareDetectionAsync: 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-located Chart.yaml.

A Containers detector category was added to DetectorClass, allowing all container-related DefaultOff detectors (Dockerfile, DockerCompose, Helm, Kubernetes) to be enabled together via --DetectorCategories Containers.

A bug in DetectorRestrictionService was also fixed: when both AllowedDetectorIds and AllowedDetectorCategories are 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

  • I have gone through the docs for creating a new detector here
  • My new detector implements IDefaultOffComponentDetector
  • I have created a PR to the verification repo with components that my new detector can find
  • (If necessary) I have updated the Feature Overview table in the README

@jpinz jpinz self-assigned this Apr 2, 2026
Copilot AI review requested due to automatic review settings April 2, 2026 21:44
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 2, 2026

👋 Hi! It looks like you modified some files in the Detectors folder.
You may need to bump the detector versions if any of the following scenarios apply:

  • The detector detects more or fewer components than before
  • The detector generates different parent/child graph relationships than before
  • The detector generates different devDependencies values than before

If none of the above scenarios apply, feel free to ignore this comment 🙂

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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, and Kubernetes detectors that parse YAML and register DockerReferenceComponent usages.
  • Register the new detectors in Orchestrator DI and extend DetectorClass with 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/kind are declared as non-nullable string and initialized to null, which will fail the build with warnings-as-errors. Make these string? (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

  • GetMappingChild returns null when the key isn't present, but the return type is non-nullable YamlMappingNode. With nullable enabled + warnings-as-errors this will fail compilation. Change the return type to YamlMappingNode? (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

  • GetSequenceChild returns null when the key isn't present, but the return type is non-nullable YamlSequenceNode. With nullable enabled + warnings-as-errors this will fail compilation. Change the return type to YamlSequenceNode? (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 string locals (repository, tag, digest, registry) to null. With nullable enabled + TreatWarningsAsErrors, this will fail the build. Use string? 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

  • GetMappingChild returns null when the key isn't present, but the return type is non-nullable YamlMappingNode. With nullable enabled + warnings-as-errors this will fail compilation. Change the return type to YamlMappingNode? 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)];
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Suggested change
public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Kubernetes)];
public override IEnumerable<string> Categories => [nameof(DetectorClass.Kubernetes)];

Copilot uses AI. Check for mistakes.

public override int Version => 1;

public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Helm)];
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Helm)];
public override IEnumerable<string> Categories => [nameof(DetectorClass.Helm)];

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +41

public override IEnumerable<ComponentType> SupportedComponentTypes => [ComponentType.DockerReference];

public override int Version => 1;

public override IEnumerable<string> Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.DockerCompose)];
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 3, 2026 15:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Comment on lines +50 to +72
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);
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 3, 2026 16:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
        }

Copilot AI review requested due to automatic review settings April 3, 2026 16:40
@jpinz jpinz marked this pull request as ready for review April 3, 2026 16:41
@jpinz jpinz requested a review from a team as a code owner April 3, 2026 16:41
@jpinz jpinz requested a review from edgarrs April 3, 2026 16:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comment on lines +125 to +138
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);
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +195 to +208
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);
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +228 to +241
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);
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces new default-off detectors to scan Docker image references from Docker Compose, Helm values, and Kubernetes manifests, wiring them into the orchestrator and extending shared Docker reference handling.

Changes:

  • Added new detectors: DockerComposeComponentDetector, HelmComponentDetector, and KubernetesComponentDetector to discover Docker image references in YAML-based configs.
  • Added a shared DockerReferenceUtility.HasUnresolvedVariables helper to skip image references containing unresolved placeholders.
  • Added unit tests for the new detectors and for the existing Dockerfile detector; registered new detectors in DI and extended DetectorClass.
Show a summary per file
File Description
test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs Adds unit tests for Kubernetes image extraction scenarios.
test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs Adds unit tests for Helm values image discovery patterns.
test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs Adds unit tests for Dockerfile image reference detection (including placeholder skipping).
test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs Adds unit tests for Docker Compose image extraction.
src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs Registers the new detectors in orchestrator DI.
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs Implements Kubernetes YAML detector for container image references.
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs Implements Helm values YAML detector for image references.
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs Implements Docker Compose YAML detector for service images.
src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs Adds DockerCompose, Helm, and Kubernetes detector classes.
src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs Adds shared unresolved-variable detection helper for Docker references.
.gitignore Ignores .nuget/ directory.

Copilot's findings

Comments suppressed due to low confidence (2)

src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs:48

  • HasUnresolvedVariables is a public utility but will throw a NullReferenceException if reference is null. Consider returning false for null/empty inputs (or throwing an ArgumentNullException consistently) so callers don’t crash unexpectedly.
    public static bool HasUnresolvedVariables(string reference) =>
        reference.IndexOfAny(['$', '{', '}']) >= 0;

src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs:200

  • The detector skips unresolved variable placeholders via DockerReferenceUtility.HasUnresolvedVariables, but there’s no unit test covering this Helm behavior (e.g., {{ .Values.image.tag }}) even though it’s called out in the PR description. Add a test to prevent regressions.
    {
        if (DockerReferenceUtility.HasUnresolvedVariables(imageReference))
        {
            return;
        }
  • Files reviewed: 10/11 changed files
  • Comments generated: 5

Comment on lines +41 to +44
public override string Id => "Kubernetes";

public override IList<string> SearchPatterns { get; } = ["*.yaml", "*.yml"];

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SearchPatterns matches all *.yaml / *.yml files, which can be extremely broad and lead to a lot of unnecessary file reads/parses in repos with many YAML files. Consider narrowing patterns (or adding a cheaper filename-based prefilter) to reduce I/O and CPU cost.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +45
/// <summary>
/// Returns true if the reference contains unresolved variable placeholders (e.g., ${VAR}, {{ .Values.tag }}).
/// Such references should be skipped before calling <see cref="ParseFamiliarName"/> or <see cref="ParseQualifiedName"/>.
/// </summary>
/// <param name="reference">The image reference string to check.</param>
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description says unresolved-variable skipping logic was consolidated across all Docker-related detectors, but DockerfileComponentDetector still has its own regex-based HasUnresolvedVariables helper and does not use this new shared method. Either update the Dockerfile detector to use DockerReferenceUtility.HasUnresolvedVariables or adjust the PR description to match the implemented scope.

This issue also appears on line 47 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +126 to +130
{
if (DockerReferenceUtility.HasUnresolvedVariables(imageReference))
{
return;
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detector skips unresolved variable placeholders via DockerReferenceUtility.HasUnresolvedVariables, but there’s no unit test covering this Docker Compose behavior (e.g., ${REGISTRY}/app:${TAG}) even though it’s called out in the PR description. Add a test to prevent regressions.

Copilot uses AI. Check for mistakes.
Comment on lines +229 to +233
{
if (DockerReferenceUtility.HasUnresolvedVariables(imageReference))
{
return;
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detector skips unresolved variable placeholders via DockerReferenceUtility.HasUnresolvedVariables, but there’s no unit test covering this Kubernetes behavior (e.g., ${REGISTRY}/app:${TAG}) even though it’s called out in the PR description. Add a test to prevent regressions.

Copilot uses AI. Check for mistakes.
@jpinz
Copy link
Copy Markdown
Member Author

jpinz commented Apr 3, 2026

@copilot apply changes based on the comments in this thread Note the response I left about the values/chart yaml files as well

…Compose, Helm, and Kubernetes when specified.
Copilot AI review requested due to automatic review settings April 3, 2026 19:36
…-location check, add unresolved variable tests

Agent-Logs-Url: https://github.com/microsoft/component-detection/sessions/cb526852-cfd1-4b40-936c-c1b2a2dfa371

Co-authored-by: jpinz <8357054+jpinz@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

@copilot apply changes based on the comments in this thread Note the response I left about the values/chart y...

Applied in commit 70762f1:

  • DockerfileComponentDetector.HasUnresolvedVariables now delegates to DockerReferenceUtility.HasUnresolvedVariables (shared across all Docker-related detectors)
  • Added TestCompose_UnresolvedVariableSkippedAsync and TestK8s_UnresolvedVariablesSkippedAsync tests
  • Implemented Helm Chart.yaml co-location check (values files skipped unless Chart.yaml is in the same directory), per @jpinz's clarification about the Chart+values file combination

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 4myvsblobprodcus32.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/BC8DF34810A5AE3AFB0D9FFAA05B0AA2/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/B9D91EC3F00925E83B2F176B451EEAFF/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D47EE5A44C32F70BEBA9A6371300F374/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 5rqvsblobprodcus385.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C8FA87C461E8D947D5E484A1822A0126/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • azuresdkartifacts.blob.core.windows.net
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp (dns block)
  • c78vsblobprodcus322.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C8FA87C461E8D947D5E484A1822A0126/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • gbsvsblobprodcus365.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C138FE768307F71762B7AEC24143E138/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • k4kvsblobprodcus344.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EAC58970BF56570ECF9A3336E1CC2C51/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • pdfvsblobprodcus380.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of jpinz April 3, 2026 19:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new DefaultOff container-focused detectors (Docker Compose, Helm values, Kubernetes manifests) to discover Docker image references from YAML, plus introduces a shared “Containers” category to enable them via --DetectorCategories.

Changes:

  • Added DockerComposeComponentDetector, HelmComponentDetector, and KubernetesComponentDetector and registered them in orchestrator DI.
  • Expanded DetectorClass with DockerCompose, Helm, Kubernetes, and Containers, and updated restriction logic/docs to support enabling DefaultOff detectors by category.
  • Added new unit tests and detector documentation pages for the new detectors (plus Dockerfile detector tests).
Show a summary per file
File Description
test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorRestrictionServiceTests.cs Adds tests validating DefaultOff detectors can be included via category restrictions.
test/Microsoft.ComponentDetection.Detectors.Tests/KubernetesComponentDetectorTests.cs New test coverage for Kubernetes YAML image extraction scenarios.
test/Microsoft.ComponentDetection.Detectors.Tests/HelmComponentDetectorTests.cs New test coverage for Helm values.yaml image extraction scenarios.
test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs Adds unit tests for Dockerfile image reference parsing behavior.
test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs New test coverage for Docker Compose image extraction scenarios.
src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorRestrictionService.cs Updates restriction logic to include DefaultOff detectors when filtering by categories.
src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs Registers the new detectors in DI.
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs Implements Kubernetes YAML detector for container image references.
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs Implements Helm values YAML detector for image references.
src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs Adds “Containers” category to Dockerfile detector.
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs Implements Docker Compose YAML detector for service image references.
src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs Adds new detector categories: DockerCompose/Helm/Kubernetes/Containers.
src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs Adds shared HasUnresolvedVariables helper for skipping templated refs.
docs/detectors/README.md Lists the new detectors in detector documentation index.
docs/detectors/kubernetes.md Adds Kubernetes detector documentation.
docs/detectors/helm.md Adds Helm detector documentation.
docs/detectors/dockerfile.md Notes container-category enabling path for Dockerfile detector.
docs/detectors/dockercompose.md Adds Docker Compose detector documentation.
docs/detector-arguments.md Documents that category selection enables matching DefaultOff detectors; adds Containers to supported categories list.
.gitignore Ignores local .nuget/ folder.

Copilot's findings

  • Files reviewed: 19/20 changed files
  • Comments generated: 2

Comment on lines +59 to +77
@@ -68,7 +68,13 @@ public IEnumerable<IComponentDetector> ApplyRestrictions(DetectorRestrictions re
}

return false;
}).ToList();
}

detectors = detectors.Where(CategoryFilter).ToList();

// Also include DefaultOff detectors whose categories match
detectors = detectors.Union(defaultOffDetectors.Where(CategoryFilter)).ToList();

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--DetectorsFilter (AllowedDetectorIds) is applied before category filtering, but the new Union(defaultOffDetectors.Where(CategoryFilter)) can re-introduce DefaultOff detectors even when a user explicitly provided a detector allow-list. If both AllowedDetectorIds and AllowedDetectorCategories are set, this effectively turns the result into a union rather than an intersection. Consider applying the AllowedDetectorIds filter after category/DefaultOff expansion (or applying it to the DefaultOff set as well) and add a regression test covering the combined options.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +48
/// <summary>
/// Returns true if the reference contains unresolved variable placeholders (e.g., ${VAR}, {{ .Values.tag }}).
/// Such references should be skipped before calling <see cref="ParseFamiliarName"/> or <see cref="ParseQualifiedName"/>.
/// </summary>
/// <param name="reference">The image reference string to check.</param>
/// <returns><c>true</c> if the reference contains variable placeholder characters; otherwise <c>false</c>.</returns>
public static bool HasUnresolvedVariables(string reference) =>
reference.IndexOfAny(['$', '{', '}']) >= 0;
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new helper duplicates the Dockerfile detector’s existing HasUnresolvedVariables implementation (Regex("[${}]")). To actually consolidate the logic across Docker-related detectors (as described in the PR), consider switching the Dockerfile detector to call this shared helper and removing the duplicate method so the criteria can’t drift over time.

Copilot uses AI. Check for mistakes.
@jpinz
Copy link
Copy Markdown
Member Author

jpinz commented Apr 3, 2026

@copilot apply changes based on the comments in this thread

Copilot AI review requested due to automatic review settings April 3, 2026 19:55
@jpinz jpinz review requested due to automatic review settings April 3, 2026 19:55
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

@copilot apply changes based on the comments in this thread

Applied in commit dff7d5f.

  • DetectorRestrictionService: when AllowedDetectorIds is set alongside AllowedDetectorCategories, DefaultOff detectors introduced via category expansion are now also filtered by the ID allow-list — producing an intersection rather than a union. The HasUnresolvedVariables consolidation was already done in the previous commit (70762f1).
  • Added WithRestrictions_DetectorIdAllowListTakesPrecedenceOverCategoryForDefaultOff regression test covering the combined options.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 4myvsblobprodcus32.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/B9D91EC3F00925E83B2F176B451EEAFF/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D47EE5A44C32F70BEBA9A6371300F374/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/CF4B41BED05CC519E28614CCFB1B4E53/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • azuresdkartifacts.blob.core.windows.net
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp (dns block)
  • c78vsblobprodcus322.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • k4kvsblobprodcus344.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • pdfvsblobprodcus380.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • st8vsblobprodcus339.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EE9D343C76C38EDF0AC64A832F8C101A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of jpinz April 3, 2026 19:56
Copilot AI review requested due to automatic review settings April 3, 2026 20:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends Component Detection’s container scanning capabilities by introducing new DefaultOff detectors for Docker Compose, Helm, and Kubernetes YAML, consolidating “unresolved variable” skipping logic, and adding a Containers detector category to enable all container-related detectors together. It also fixes detector restriction behavior so that category expansion respects an explicit detector ID allow-list (intersection instead of union).

Changes:

  • Added new DefaultOff detectors: DockerComposeComponentDetector, HelmComponentDetector, KubernetesComponentDetector, and registered them in orchestrator DI.
  • Added DetectorClass.Containers (and related per-detector categories) and updated CLI/docs accordingly.
  • Centralized unresolved-variable skipping with DockerReferenceUtility.HasUnresolvedVariables and updated Dockerfile detector + added tests.
Show a summary per file
File Description
test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorRestrictionServiceTests.cs Adds test coverage for category-based enabling of DefaultOff detectors and for the allow-list intersection fix.
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 patterns (direct/structured images, digests, skipping).
test/Microsoft.ComponentDetection.Detectors.Tests/DockerfileComponentDetectorTests.cs Adds unit tests for Dockerfile detector behavior including unresolved-variable skipping and digest handling.
test/Microsoft.ComponentDetection.Detectors.Tests/DockerComposeComponentDetectorTests.cs Adds unit tests for Docker Compose YAML image extraction and skipping unresolved variables.
src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorRestrictionService.cs Fixes restriction logic so DefaultOff detectors introduced via category expansion are constrained by AllowedDetectorIds when provided.
src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs Registers the new detectors in DI.
src/Microsoft.ComponentDetection.Detectors/kubernetes/KubernetesComponentDetector.cs New Kubernetes YAML detector that extracts container image references.
src/Microsoft.ComponentDetection.Detectors/helm/HelmComponentDetector.cs New Helm detector intended to parse values files when a Chart file is co-located.
src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs Updates categories to include Containers and switches unresolved-variable detection to shared utility.
src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs New Docker Compose detector that extracts service image: references.
src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs Adds DockerCompose, Helm, Kubernetes, and Containers detector classes/categories.
src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs Adds HasUnresolvedVariables helper used across container-related detectors.
docs/detectors/README.md Documents the new detectors in the detector docs index.
docs/detectors/kubernetes.md Adds Kubernetes detector documentation.
docs/detectors/helm.md Adds Helm detector documentation.
docs/detectors/dockerfile.md Updates Dockerfile docs to mention enabling via --DetectorCategories Containers.
docs/detectors/dockercompose.md Adds Docker Compose detector documentation.
docs/detector-arguments.md Updates --DetectorCategories documentation to mention DefaultOff category enabling and Containers.
.gitignore Ignores .nuget/.

Copilot's findings

  • Files reviewed: 19/20 changed files
  • Comments generated: 6

Comment on lines +65 to +74
// Only process values files — and only when co-located with a Chart.yaml in the same directory.
if (!IsValuesFile(fileName))
{
return;
}

if (!this.helmChartDirectories.ContainsKey(directory))
{
return;
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Values files are only processed if helmChartDirectories already contains the directory, but file enumeration order isn’t guaranteed. If a values file is observed before its Chart file, it will be skipped and never re-processed, causing missed detections. Consider checking for a co-located Chart file on demand (e.g., via file existence) or building the chart-directory set up-front in OnPrepareDetectionAsync before processing values files.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in commit 7f08f43. Replaced the single-pass OnFileFoundAsync approach with a two-pass OnPrepareDetectionAsync (following the pattern used by GoComponentDetector): 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 the ordering dependency entirely. Added TestHelm_ValuesFileObservedBeforeChartYamlAsync to cover the values-before-chart enumeration scenario.

Copilot AI review requested due to automatic review settings April 3, 2026 20:41
@jpinz jpinz review requested due to automatic review settings April 3, 2026 20:41
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 5rqvsblobprodcus385.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/D93C69A3F90DACDB68555AD6306FA9CB/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • azuresdkartifacts.blob.core.windows.net
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp (dns block)
  • c78vsblobprodcus322.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/86123D718A0A7D5E3D8DDB87D50A845A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • k4kvsblobprodcus344.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/EAC58970BF56570ECF9A3336E1CC2C51/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • pdfvsblobprodcus380.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/2D3586D8C912F6D195254B43F0F0042B/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/4EB20032E82B2584A5C53CFFE5CD470A/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/C8FA87C461E8D947D5E484A1822A0126/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • s8mvsblobprodcus38.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/50B984F0373F12A39D028856910588FC/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • ytvvsblobprodcus310.vsblob.vsassets.io
    • Triggering command: /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/A57A5A89CDBA36A2878C8A42DA58182C/missingpackages_workingdir --packages /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-fe72422a9cf5c763/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of jpinz April 3, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants