From 43954568fdb932b33c608757f05275aab221297c Mon Sep 17 00:00:00 2001 From: Dan Cristoloveanu Date: Wed, 30 Sep 2026 19:37:39 -0700 Subject: [PATCH 1/2] Update Valleysoft.DockerfileModel to 2.0.0 for heredoc support Valleysoft.DockerfileModel 1.2.0 predates BuildKit heredoc support, so any Dockerfile using RUN/COPY < --- Directory.Packages.props | 2 +- docs/detectors/dockerfile.md | 2 + .../DockerfileComponentDetectorTests.cs | 124 ++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d1cf38c0c..21e67f6a1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -48,7 +48,7 @@ - + diff --git a/docs/detectors/dockerfile.md b/docs/detectors/dockerfile.md index 2da4fa3a4..febfad138 100644 --- a/docs/detectors/dockerfile.md +++ b/docs/detectors/dockerfile.md @@ -12,6 +12,8 @@ The `DockerfileComponentDetector` is an **Experimental** detector. It runs autom The Dockerfile detector parses Dockerfile syntax to extract Docker image references from `FROM` and `COPY --from` instructions. It uses the [Valleysoft.DockerfileModel](https://github.com/mthalman/DockerfileModel) library to parse Dockerfile syntax. +BuildKit [here-documents](https://docs.docker.com/reference/dockerfile/#here-documents) (for example `RUN <>(); + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("Dockerfile", dockerfile) + .AddServiceMock(loggerMock) + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + var components = componentRecorder.GetDetectedComponents(); + components.Should().ContainSingle(); + + var dockerRef = components.First().Component as DockerReferenceComponent; + dockerRef.Should().NotBeNull(); + dockerRef!.Repository.Should().Be("library/ubuntu"); + dockerRef.Tag.Should().Be("noble"); + + loggerMock.Verify( + logger => logger.Log( + It.Is(level => level >= LogLevel.Warning), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny>()), + Times.Never); + } + + [TestMethod] + public async Task TestDockerfile_RunHeredocWithInterpreterAndSyntaxDirectiveAsync() + { + var dockerfile = @"# syntax=docker/dockerfile:1.4 +FROM ubuntu:noble-20260113 + +RUN < c.Component as DockerReferenceComponent) + .Where(c => c != null) + .Select(c => c!.Repository) + .ToList(); + repos.Should().Contain("dotnet/sdk"); + repos.Should().Contain("dotnet/runtime-deps"); + } + + [TestMethod] + public async Task TestDockerfile_HeredocBodyIsNotParsedAsInstructionsAsync() + { + // A heredoc body is opaque content, so a FROM line inside it is not a base image. + var dockerfile = @" +FROM alpine:3.20 +RUN < /tmp/Dockerfile.inner +FROM inner/image:1.0 +EOF +"; + + var (scanResult, componentRecorder) = await this.DetectorTestUtility + .WithFile("Dockerfile", dockerfile) + .ExecuteDetectorAsync(); + + scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); + var components = componentRecorder.GetDetectedComponents(); + components.Should().ContainSingle(); + + var dockerRef = components.First().Component as DockerReferenceComponent; + dockerRef.Should().NotBeNull(); + dockerRef!.Repository.Should().Be("library/alpine"); + dockerRef.Tag.Should().Be("3.20"); + } } From bf5d57747b4824b7510c867b87def7469e770926 Mon Sep 17 00:00:00 2001 From: Dan Cristoloveanu Date: Thu, 1 Oct 2026 19:01:43 -0700 Subject: [PATCH 2/2] Bump DockerfileComponentDetector version to 2 Heredoc Dockerfiles that were previously skipped now produce components, which the detector version policy treats as an output change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dockerfile/DockerfileComponentDetector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs index 00760e336..72f9dbcf9 100644 --- a/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs @@ -42,7 +42,7 @@ public DockerfileComponentDetector( public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.DockerReference]; - public override int Version => 1; + public override int Version => 2; protected override IList SkippedFolders => ["node_modules"];