Skip to content

Commit 7e8f1ef

Browse files
jpinzCopilot
andcommitted
Add logging to some of the utils in DockerReferenceUtility for parse failures
Co-authored-by: Copilot <copilot@github.com>
1 parent fbfec90 commit 7e8f1ef

4 files changed

Lines changed: 58 additions & 24 deletions

File tree

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

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace Microsoft.ComponentDetection.Common;
2929
using System;
3030
using System.Diagnostics.CodeAnalysis;
3131
using Microsoft.ComponentDetection.Contracts;
32+
using Microsoft.Extensions.Logging;
3233

3334
public static class DockerReferenceUtility
3435
{
@@ -49,32 +50,53 @@ public static bool HasUnresolvedVariables(string reference) =>
4950

5051
/// <summary>
5152
/// Attempts to parse an image reference string into a <see cref="DockerReference"/>.
52-
/// Returns <c>null</c> if the reference contains unresolved variables.
53+
/// Returns <c>null</c> if the reference contains unresolved variables or cannot be parsed.
5354
/// </summary>
5455
/// <param name="imageReference">The image reference string to parse.</param>
55-
/// <returns>A <see cref="DockerReference"/> if parsing succeeds; otherwise <c>null</c> if it has unresolved variables, or an exception is thrown.</returns>
56-
public static DockerReference? TryParseImageReference(string imageReference)
56+
/// <param name="logger">Optional logger for recording parse failures.</param>
57+
/// <returns>A <see cref="DockerReference"/> if parsing succeeds; otherwise <c>null</c>.</returns>
58+
public static DockerReference? TryParseImageReference(string imageReference, ILogger? logger = null)
5759
{
5860
if (HasUnresolvedVariables(imageReference))
5961
{
6062
return null;
6163
}
6264

63-
return ParseFamiliarName(imageReference);
65+
try
66+
{
67+
return ParseFamiliarName(imageReference);
68+
}
69+
catch (DockerReferenceException ex)
70+
{
71+
logger?.LogWarning(ex, "Failed to parse image reference '{ImageReference}'.", imageReference);
72+
return null;
73+
}
6474
}
6575

6676
/// <summary>
6777
/// Parses an image reference and registers it with the recorder if valid.
68-
/// Silently skips references with unresolved variables or that cannot be parsed.
78+
/// Skips references with unresolved variables or that cannot be parsed,
79+
/// logging a warning for parse failures so that remaining entries continue to be processed.
6980
/// </summary>
7081
/// <param name="imageReference">The image reference string to parse.</param>
7182
/// <param name="recorder">The component recorder to register the image with.</param>
72-
public static void TryRegisterImageReference(string imageReference, ISingleFileComponentRecorder recorder)
83+
/// <param name="logger">Optional logger for recording parse failures.</param>
84+
public static void TryRegisterImageReference(string imageReference, ISingleFileComponentRecorder recorder, ILogger? logger = null)
85+
{
86+
var dockerRef = TryParseImageReference(imageReference, logger);
87+
TryRegisterImageReference(dockerRef, recorder);
88+
}
89+
90+
/// <summary>
91+
/// Registers a pre-parsed <see cref="DockerReference"/> with the recorder if non-null.
92+
/// </summary>
93+
/// <param name="dockerReference">The parsed docker reference, or <c>null</c> to skip.</param>
94+
/// <param name="recorder">The component recorder to register the image with.</param>
95+
public static void TryRegisterImageReference(DockerReference? dockerReference, ISingleFileComponentRecorder recorder)
7396
{
74-
var dockerRef = TryParseImageReference(imageReference);
75-
if (dockerRef != null)
97+
if (dockerReference != null)
7698
{
77-
recorder.RegisterUsage(new DetectedComponent(dockerRef.ToTypedDockerReferenceComponent()));
99+
recorder.RegisterUsage(new DetectedComponent(dockerReference.ToTypedDockerReferenceComponent()));
78100
}
79101
}
80102

src/Microsoft.ComponentDetection.Detectors/dockercompose/DockerComposeComponentDetector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private void ExtractImageReferences(YamlMappingNode rootMapping, ISingleFileComp
114114
var imageRef = (entry.Value as YamlScalarNode)?.Value;
115115
if (!string.IsNullOrWhiteSpace(imageRef))
116116
{
117-
DockerReferenceUtility.TryRegisterImageReference(imageRef, recorder);
117+
DockerReferenceUtility.TryRegisterImageReference(imageRef, recorder, this.Logger);
118118
}
119119
}
120120
}

src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,7 @@ private Task ParseDockerFileAsync(string fileContents, string fileLocation, ISin
7272
foreach (var instruction in instructions)
7373
{
7474
var imageReference = this.ProcessDockerfileConstruct(instruction, dockerfileModel.EscapeChar, stageNameMap);
75-
if (imageReference != null)
76-
{
77-
singleFileComponentRecorder.RegisterUsage(new DetectedComponent(imageReference.ToTypedDockerReferenceComponent()));
78-
}
75+
DockerReferenceUtility.TryRegisterImageReference(imageReference, singleFileComponentRecorder);
7976
}
8077

8178
return Task.CompletedTask;
@@ -85,14 +82,12 @@ private Task ParseDockerFileAsync(string fileContents, string fileLocation, ISin
8582
{
8683
try
8784
{
88-
var baseImage = construct switch
85+
return construct switch
8986
{
9087
FromInstruction => this.ParseFromInstruction(construct, escapeChar, stageNameMap),
9188
CopyInstruction => this.ParseCopyInstruction(construct, escapeChar, stageNameMap),
9289
_ => null,
9390
};
94-
95-
return baseImage;
9691
}
9792
catch (Exception e)
9893
{

test/Microsoft.ComponentDetection.Common.Tests/DockerReferenceUtilityTests.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Microsoft.ComponentDetection.Common.Tests;
55
using AwesomeAssertions;
66
using Microsoft.ComponentDetection.Contracts;
77
using Microsoft.ComponentDetection.Contracts.BcdeModels;
8+
using Microsoft.Extensions.Logging;
89
using Microsoft.VisualStudio.TestTools.UnitTesting;
910
using Moq;
1011

@@ -296,11 +297,9 @@ public void TryParseImageReference_ReturnsNullForUnresolvedVariables()
296297
}
297298

298299
[TestMethod]
299-
public void TryParseImageReference_ThrowsForInvalidReference()
300+
public void TryParseImageReference_ReturnsNullForInvalidReference()
300301
{
301-
var func = () => DockerReferenceUtility.TryParseImageReference("docker.io/library/Nginx");
302-
303-
func.Should().Throw<ReferenceNameContainsUppercaseException>();
302+
DockerReferenceUtility.TryParseImageReference("docker.io/library/Nginx").Should().BeNull();
304303
}
305304

306305
[TestMethod]
@@ -357,13 +356,31 @@ public void TryRegisterImageReference_SkipsUnresolvedVariables()
357356
}
358357

359358
[TestMethod]
360-
public void TryRegisterImageReference_ThrowsForInvalidReference()
359+
public void TryRegisterImageReference_SkipsInvalidReference()
361360
{
362361
var recorder = new Mock<ISingleFileComponentRecorder>();
363362

364-
var func = () => DockerReferenceUtility.TryRegisterImageReference("docker.io/library/Nginx", recorder.Object);
363+
DockerReferenceUtility.TryRegisterImageReference("docker.io/library/Nginx", recorder.Object);
364+
365+
recorder.Verify(r => r.RegisterUsage(It.IsAny<DetectedComponent>(), It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<bool?>(), It.IsAny<DependencyScope?>(), It.IsAny<string>()), Times.Never);
366+
}
367+
368+
[TestMethod]
369+
public void TryRegisterImageReference_LogsWarningForInvalidReference()
370+
{
371+
var recorder = new Mock<ISingleFileComponentRecorder>();
372+
var logger = new Mock<ILogger>();
373+
374+
DockerReferenceUtility.TryRegisterImageReference("docker.io/library/Nginx", recorder.Object, logger.Object);
365375

366-
func.Should().Throw<ReferenceNameContainsUppercaseException>();
367376
recorder.Verify(r => r.RegisterUsage(It.IsAny<DetectedComponent>(), It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<bool?>(), It.IsAny<DependencyScope?>(), It.IsAny<string>()), Times.Never);
377+
logger.Verify(
378+
l => l.Log(
379+
LogLevel.Warning,
380+
It.IsAny<EventId>(),
381+
It.IsAny<It.IsAnyType>(),
382+
It.IsAny<Exception>(),
383+
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
384+
Times.Once);
368385
}
369386
}

0 commit comments

Comments
 (0)