diff --git a/.gitignore b/.gitignore
index 533090632..1a86942c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,3 +54,4 @@ launchSettings.json
# Dev nupkgs
dev-source
+.nuget/
diff --git a/docs/detectors/dockerfile.md b/docs/detectors/dockerfile.md
index 8143c031a..9206d3d20 100644
--- a/docs/detectors/dockerfile.md
+++ b/docs/detectors/dockerfile.md
@@ -29,4 +29,4 @@ The detector attempts to resolve Dockerfile variables using the `ResolveVariable
- **DefaultOff Status**: This detector must be explicitly enabled using `--DetectorArgs DockerReference=EnableIfDefaultOff`
- **Variable Resolution**: Image references containing unresolved Dockerfile `ARG` or `ENV` variables are not reported, which may lead to under-reporting in Dockerfiles that heavily use build-time variables
- **No Version Pinning Validation**: The detector does not warn about unpinned image versions (e.g., `latest` tags), which are generally discouraged in production Dockerfiles
-- **No Digest Support**: While Docker supports content-addressable image references using SHA256 digests (e.g., `ubuntu@sha256:abc...`), the parsing and reporting of these references depends on the underlying `DockerReferenceUtility.ParseFamiliarName()` implementation
+- **No Digest Support**: While Docker supports content-addressable image references using SHA256 digests (e.g., `ubuntu@sha256:abc...`), the parsing and reporting of these references depends on the underlying `ContainerImageReferenceUtility.ParseFamiliarName()` implementation
diff --git a/docs/schema/manifest.schema.json b/docs/schema/manifest.schema.json
index 0db3bdc7d..5bce9dc0d 100644
--- a/docs/schema/manifest.schema.json
+++ b/docs/schema/manifest.schema.json
@@ -150,6 +150,7 @@
"Conda",
"Spdx",
"Vcpkg",
+ "ContainerImageReference",
"DockerReference",
"Conan",
"Swift",
@@ -424,6 +425,7 @@
"Conda",
"Spdx",
"Vcpkg",
+ "ContainerImageReference",
"DockerReference",
"Conan",
"Swift",
diff --git a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceException.cs b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageReferenceException.cs
similarity index 79%
rename from src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceException.cs
rename to src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageReferenceException.cs
index 1ef1fec97..47c2d76e1 100644
--- a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceException.cs
+++ b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageReferenceException.cs
@@ -3,30 +3,30 @@ namespace Microsoft.ComponentDetection.Common;
using System;
-internal class DockerReferenceException : Exception
+internal class ContainerImageReferenceException : Exception
{
- public DockerReferenceException(string reference, string exceptionErrorMessage)
- : base($"Error while parsing docker reference {reference} : {exceptionErrorMessage}")
+ public ContainerImageReferenceException(string reference, string exceptionErrorMessage)
+ : base($"Error while parsing container image reference {reference} : {exceptionErrorMessage}")
{
}
- public DockerReferenceException()
+ public ContainerImageReferenceException()
{
}
- public DockerReferenceException(string message)
+ public ContainerImageReferenceException(string message)
: base(message)
{
}
- public DockerReferenceException(string message, Exception innerException)
+ public ContainerImageReferenceException(string message, Exception innerException)
: base(message, innerException)
{
}
}
// ReferenceInvalidFormat represents an error while trying to parse a string as a reference.
-internal class ReferenceInvalidFormatException : DockerReferenceException
+internal class ReferenceInvalidFormatException : ContainerImageReferenceException
{
private const string ErrorMessage = "invalid reference format";
@@ -46,7 +46,7 @@ public ReferenceInvalidFormatException(string message, Exception innerException)
}
// TagInvalidFormat represents an error while trying to parse a string as a tag.
-internal class ReferenceTagInvalidFormatException : DockerReferenceException
+internal class ReferenceTagInvalidFormatException : ContainerImageReferenceException
{
private const string ErrorMessage = "invalid tag format";
@@ -66,7 +66,7 @@ public ReferenceTagInvalidFormatException(string message, Exception innerExcepti
}
// DigestInvalidFormat represents an error while trying to parse a string as a tag.
-internal class ReferenceDigestInvalidFormatException : DockerReferenceException
+internal class ReferenceDigestInvalidFormatException : ContainerImageReferenceException
{
private const string ErrorMessage = "invalid digest format";
@@ -86,7 +86,7 @@ public ReferenceDigestInvalidFormatException(string message, Exception innerExce
}
// NameContainsUppercase is returned for invalid repository names that contain uppercase characters.
-internal class ReferenceNameContainsUppercaseException : DockerReferenceException
+internal class ReferenceNameContainsUppercaseException : ContainerImageReferenceException
{
private const string ErrorMessage = "repository name must be lowercase";
@@ -106,7 +106,7 @@ public ReferenceNameContainsUppercaseException(string message, Exception innerEx
}
// NameEmpty is returned for empty, invalid repository names.
-internal class ReferenceNameEmptyException : DockerReferenceException
+internal class ReferenceNameEmptyException : ContainerImageReferenceException
{
private const string ErrorMessage = "repository name must have at least one component";
@@ -126,7 +126,7 @@ public ReferenceNameEmptyException(string message, Exception innerException)
}
// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
-internal class ReferenceNameTooLongException : DockerReferenceException
+internal class ReferenceNameTooLongException : ContainerImageReferenceException
{
private const string ErrorMessage = "repository name must not be more than 255 characters";
@@ -146,7 +146,7 @@ public ReferenceNameTooLongException(string message, Exception innerException)
}
// ErrNameNotCanonical is returned when a name is not canonical.
-internal class ReferenceNameNotCanonicalException : DockerReferenceException
+internal class ReferenceNameNotCanonicalException : ContainerImageReferenceException
{
private const string ErrorMessage = "repository name must be canonical";
@@ -165,7 +165,7 @@ public ReferenceNameNotCanonicalException(string message, Exception innerExcepti
}
}
-internal class InvalidDigestFormatError : DockerReferenceException
+internal class InvalidDigestFormatError : ContainerImageReferenceException
{
private const string ErrorMessage = "invalid digest format";
@@ -184,7 +184,7 @@ public InvalidDigestFormatError(string message, Exception innerException)
}
}
-internal class UnsupportedAlgorithmError : DockerReferenceException
+internal class UnsupportedAlgorithmError : ContainerImageReferenceException
{
private const string ErrorMessage = "unsupported digest algorithm";
@@ -203,7 +203,7 @@ public UnsupportedAlgorithmError(string message, Exception innerException)
}
}
-internal class InvalidDigestLengthError : DockerReferenceException
+internal class InvalidDigestLengthError : ContainerImageReferenceException
{
private const string ErrorMessage = "invalid checksum digest length";
diff --git a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageReferenceUtility.cs
similarity index 83%
rename from src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs
rename to src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageReferenceUtility.cs
index 022f8b612..1a088292c 100644
--- a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs
+++ b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageReferenceUtility.cs
@@ -30,7 +30,7 @@ namespace Microsoft.ComponentDetection.Common;
using System.Diagnostics.CodeAnalysis;
using Microsoft.ComponentDetection.Contracts;
-public static class DockerReferenceUtility
+public static class ContainerImageReferenceUtility
{
// NameTotalLengthMax is the maximum total number of characters in a repository name.
private const int NameTotalLengthMax = 255;
@@ -38,9 +38,9 @@ public static class DockerReferenceUtility
private const string LEGACYDEFAULTDOMAIN = "index.docker.io";
private const string OFFICIALREPOSITORYNAME = "library";
- public static DockerReference ParseQualifiedName(string qualifiedName)
+ public static ContainerImageReference ParseQualifiedName(string qualifiedName)
{
- var regexp = DockerRegex.ReferenceRegexp;
+ var regexp = ContainerImageRegex.ReferenceRegexp;
if (!regexp.IsMatch(qualifiedName))
{
if (string.IsNullOrWhiteSpace(qualifiedName))
@@ -66,7 +66,7 @@ public static DockerReference ParseQualifiedName(string qualifiedName)
var reference = new Reference();
- var nameMatch = DockerRegex.AnchoredNameRegexp.Match(name).Groups;
+ var nameMatch = ContainerImageRegex.AnchoredNameRegexp.Match(name).Groups;
if (nameMatch.Count == 3)
{
reference.Domain = nameMatch[1].Value;
@@ -86,7 +86,7 @@ public static DockerReference ParseQualifiedName(string qualifiedName)
reference.Digest = matches[3].Value;
}
- return CreateDockerReference(reference);
+ return CreateContainerImageReference(reference);
}
public static (string Domain, string Remainder) SplitDockerDomain(string name)
@@ -123,9 +123,9 @@ public static (string Domain, string Remainder) SplitDockerDomain(string name)
}
[SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Explicitly checks for character case.")]
- public static DockerReference ParseFamiliarName(string name)
+ public static ContainerImageReference ParseFamiliarName(string name)
{
- if (DockerRegex.AnchoredIdentifierRegexp.IsMatch(name))
+ if (ContainerImageRegex.AnchoredIdentifierRegexp.IsMatch(name))
{
throw new ReferenceNameNotCanonicalException(name);
}
@@ -151,23 +151,23 @@ public static DockerReference ParseFamiliarName(string name)
return ParseQualifiedName($"{domain}/{remainder}");
}
- public static DockerReference ParseAll(string name)
+ public static ContainerImageReference ParseAll(string name)
{
- if (DockerRegex.AnchoredIdentifierRegexp.IsMatch(name))
+ if (ContainerImageRegex.AnchoredIdentifierRegexp.IsMatch(name))
{
- return CreateDockerReference(new Reference { Digest = $"sha256:{name}" });
+ return CreateContainerImageReference(new Reference { Digest = $"sha256:{name}" });
}
if (DigestUtility.CheckDigest(name, false))
{
- return CreateDockerReference(new Reference { Digest = name });
+ return CreateContainerImageReference(new Reference { Digest = name });
}
return ParseFamiliarName(name);
}
- private static DockerReference CreateDockerReference(Reference options)
+ private static ContainerImageReference CreateContainerImageReference(Reference options)
{
- return DockerReference.CreateDockerReference(options.Repository, options.Domain, options.Digest, options.Tag);
+ return ContainerImageReference.CreateContainerImageReference(options.Repository, options.Domain, options.Digest, options.Tag);
}
}
diff --git a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerRegex.cs b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageRegex.cs
similarity index 99%
rename from src/Microsoft.ComponentDetection.Common/DockerReference/DockerRegex.cs
rename to src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageRegex.cs
index 4e9af5a68..ba95c2fab 100644
--- a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerRegex.cs
+++ b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/ContainerImageRegex.cs
@@ -3,7 +3,7 @@ namespace Microsoft.ComponentDetection.Common;
using System.Linq;
using System.Text.RegularExpressions;
-public static class DockerRegex
+public static class ContainerImageRegex
{
public static readonly Regex AlphaNumericRegexp = new Regex("[a-z0-9]+");
public static readonly Regex SeparatorRegexp = new Regex("(?:[._]|__|[-]*)");
diff --git a/src/Microsoft.ComponentDetection.Common/DockerReference/DigestUtility.cs b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/DigestUtility.cs
similarity index 94%
rename from src/Microsoft.ComponentDetection.Common/DockerReference/DigestUtility.cs
rename to src/Microsoft.ComponentDetection.Common/ContainerImageReference/DigestUtility.cs
index b1871c487..f8c83e7bf 100644
--- a/src/Microsoft.ComponentDetection.Common/DockerReference/DigestUtility.cs
+++ b/src/Microsoft.ComponentDetection.Common/ContainerImageReference/DigestUtility.cs
@@ -16,7 +16,7 @@ public static bool CheckDigest(string digest, bool throwError = true)
var indexOfColon = digest.IndexOf(':');
if (indexOfColon < 0 ||
indexOfColon + 1 == digest.Length ||
- !DockerRegex.AnchoredDigestRegexp.IsMatch(digest))
+ !ContainerImageRegex.AnchoredDigestRegexp.IsMatch(digest))
{
if (throwError)
{
diff --git a/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentMapping.cs b/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentMapping.cs
index 84661e658..bce3f06ba 100644
--- a/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentMapping.cs
+++ b/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentMapping.cs
@@ -31,7 +31,8 @@ internal static class TypedComponentMapping
{ nameof(ComponentType.Pod), typeof(PodComponent) },
{ nameof(ComponentType.Linux), typeof(LinuxComponent) },
{ nameof(ComponentType.Conda), typeof(CondaComponent) },
- { nameof(ComponentType.DockerReference), typeof(DockerReferenceComponent) },
+ { nameof(ComponentType.ContainerImageReference), typeof(ContainerImageReferenceComponent) },
+ { "DockerReference", typeof(ContainerImageReferenceComponent) },
{ nameof(ComponentType.Vcpkg), typeof(VcpkgComponent) },
{ nameof(ComponentType.Spdx), typeof(SpdxComponent) },
{ nameof(ComponentType.DotNet), typeof(DotNetComponent) },
diff --git a/src/Microsoft.ComponentDetection.Contracts/DockerReference.cs b/src/Microsoft.ComponentDetection.Contracts/ContainerImageReference.cs
similarity index 64%
rename from src/Microsoft.ComponentDetection.Contracts/DockerReference.cs
rename to src/Microsoft.ComponentDetection.Contracts/ContainerImageReference.cs
index 044a3bbfd..70579cc92 100644
--- a/src/Microsoft.ComponentDetection.Contracts/DockerReference.cs
+++ b/src/Microsoft.ComponentDetection.Contracts/ContainerImageReference.cs
@@ -1,7 +1,7 @@
#nullable disable
namespace Microsoft.ComponentDetection.Contracts;
-public enum DockerReferenceKind
+public enum ContainerImageReferenceKind
{
Canonical = 0,
Repository = 1,
@@ -11,11 +11,11 @@ public enum DockerReferenceKind
}
#pragma warning disable SA1402
-public class DockerReference
+public class ContainerImageReference
{
- public virtual DockerReferenceKind Kind { get; }
+ public virtual ContainerImageReferenceKind Kind { get; }
- public static DockerReference CreateDockerReference(string repository, string domain, string digest, string tag)
+ public static ContainerImageReference CreateContainerImageReference(string repository, string domain, string digest, string tag)
{
if (!string.IsNullOrEmpty(repository) && string.IsNullOrEmpty(domain))
{
@@ -72,7 +72,7 @@ public static DockerReference CreateDockerReference(string repository, string do
}
}
- public virtual TypedComponent.DockerReferenceComponent ToTypedDockerReferenceComponent()
+ public virtual TypedComponent.ContainerImageReferenceComponent ToTypedContainerImageReferenceComponent()
{
throw new System.NotImplementedException();
}
@@ -90,20 +90,20 @@ public class Reference
}
// sha256:abc123...
-public class DigestReference : DockerReference
+public class DigestReference : ContainerImageReference
{
public string Digest { get; set; }
- public override DockerReferenceKind Kind { get; } = DockerReferenceKind.Digest;
+ public override ContainerImageReferenceKind Kind { get; } = ContainerImageReferenceKind.Digest;
public override string ToString()
{
return $"{this.Digest}";
}
- public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceComponent()
+ public override TypedComponent.ContainerImageReferenceComponent ToTypedContainerImageReferenceComponent()
{
- return new TypedComponent.DockerReferenceComponent(this)
+ return new TypedComponent.ContainerImageReferenceComponent(this)
{
Digest = this.Digest,
};
@@ -111,7 +111,7 @@ public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceCo
}
// docker.io/library/ubuntu@sha256:abc123...
-public class CanonicalReference : DockerReference
+public class CanonicalReference : ContainerImageReference
{
public string Domain { get; set; }
@@ -119,16 +119,16 @@ public class CanonicalReference : DockerReference
public string Digest { get; set; }
- public override DockerReferenceKind Kind { get; } = DockerReferenceKind.Canonical;
+ public override ContainerImageReferenceKind Kind { get; } = ContainerImageReferenceKind.Canonical;
public override string ToString()
{
return $"{this.Domain}/{this.Repository}@${this.Digest}";
}
- public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceComponent()
+ public override TypedComponent.ContainerImageReferenceComponent ToTypedContainerImageReferenceComponent()
{
- return new TypedComponent.DockerReferenceComponent(this)
+ return new TypedComponent.ContainerImageReferenceComponent(this)
{
Domain = this.Domain,
Digest = this.Digest,
@@ -138,22 +138,22 @@ public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceCo
}
// docker.io/library/ubuntu
-public class RepositoryReference : DockerReference
+public class RepositoryReference : ContainerImageReference
{
public string Domain { get; set; }
public string Repository { get; set; }
- public override DockerReferenceKind Kind { get; } = DockerReferenceKind.Repository;
+ public override ContainerImageReferenceKind Kind { get; } = ContainerImageReferenceKind.Repository;
public override string ToString()
{
return $"{this.Repository}";
}
- public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceComponent()
+ public override TypedComponent.ContainerImageReferenceComponent ToTypedContainerImageReferenceComponent()
{
- return new TypedComponent.DockerReferenceComponent(this)
+ return new TypedComponent.ContainerImageReferenceComponent(this)
{
Domain = this.Domain,
Repository = this.Repository,
@@ -162,7 +162,7 @@ public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceCo
}
// docker.io/library/ubuntu:latest
-public class TaggedReference : DockerReference
+public class TaggedReference : ContainerImageReference
{
public string Domain { get; set; }
@@ -170,16 +170,16 @@ public class TaggedReference : DockerReference
public string Tag { get; set; }
- public override DockerReferenceKind Kind { get; } = DockerReferenceKind.Tagged;
+ public override ContainerImageReferenceKind Kind { get; } = ContainerImageReferenceKind.Tagged;
public override string ToString()
{
return $"{this.Domain}/{this.Repository}:${this.Tag}";
}
- public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceComponent()
+ public override TypedComponent.ContainerImageReferenceComponent ToTypedContainerImageReferenceComponent()
{
- return new TypedComponent.DockerReferenceComponent(this)
+ return new TypedComponent.ContainerImageReferenceComponent(this)
{
Domain = this.Domain,
Tag = this.Tag,
@@ -189,7 +189,7 @@ public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceCo
}
// docker.io/library/ubuntu:latest@sha256:abc123...
-public class DualReference : DockerReference
+public class DualReference : ContainerImageReference
{
public string Domain { get; set; }
@@ -199,16 +199,16 @@ public class DualReference : DockerReference
public string Digest { get; set; }
- public override DockerReferenceKind Kind { get; } = DockerReferenceKind.Dual;
+ public override ContainerImageReferenceKind Kind { get; } = ContainerImageReferenceKind.Dual;
public override string ToString()
{
return $"{this.Domain}/{this.Repository}:${this.Tag}@${this.Digest}";
}
- public override TypedComponent.DockerReferenceComponent ToTypedDockerReferenceComponent()
+ public override TypedComponent.ContainerImageReferenceComponent ToTypedContainerImageReferenceComponent()
{
- return new TypedComponent.DockerReferenceComponent(this)
+ return new TypedComponent.ContainerImageReferenceComponent(this)
{
Domain = this.Domain,
Digest = this.Digest,
diff --git a/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs b/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs
index becfa4f9f..dc15d8233 100644
--- a/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs
+++ b/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs
@@ -42,8 +42,8 @@ public enum DetectorClass
/// Indicates a detector applies to Vcpkg packages.
Vcpkg,
- /// Indicates a detector applies to Docker references.
- DockerReference,
+ /// Indicates a detector applies to container image references.
+ ContainerImageReference,
/// Indicates a detector applies to Swift packages.
Swift,
diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs
index 391bc82bc..1f87ffdae 100644
--- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs
+++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs
@@ -1,5 +1,6 @@
namespace Microsoft.ComponentDetection.Contracts.TypedComponent;
+using System;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
@@ -54,7 +55,12 @@ public enum ComponentType : byte
Vcpkg = 15,
[EnumMember]
- DockerReference = 16,
+ ContainerImageReference = 16,
+
+ /// Deprecated. Backward compatibility alias for . This alias will be removed in a future major version. Use instead.
+ [EnumMember]
+ [Obsolete("Use ContainerImageReference instead.")]
+ DockerReference = ContainerImageReference,
[EnumMember]
Conan = 17,
diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/DockerReferenceComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ContainerImageReferenceComponent.cs
similarity index 56%
rename from src/Microsoft.ComponentDetection.Contracts/TypedComponent/DockerReferenceComponent.cs
rename to src/Microsoft.ComponentDetection.Contracts/TypedComponent/ContainerImageReferenceComponent.cs
index 8c0c6330d..1041a3a08 100644
--- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/DockerReferenceComponent.cs
+++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ContainerImageReferenceComponent.cs
@@ -3,20 +3,20 @@ namespace Microsoft.ComponentDetection.Contracts.TypedComponent;
using System.Text.Json.Serialization;
-public class DockerReferenceComponent : TypedComponent
+public class ContainerImageReferenceComponent : TypedComponent
{
- public DockerReferenceComponent(string hash, string repository = null, string tag = null)
+ public ContainerImageReferenceComponent(string hash, string repository = null, string tag = null)
{
- this.Digest = this.ValidateRequiredInput(hash, nameof(this.Digest), nameof(ComponentType.DockerReference));
+ this.Digest = this.ValidateRequiredInput(hash, nameof(this.Digest), nameof(ComponentType.ContainerImageReference));
this.Repository = repository;
this.Tag = tag;
}
- public DockerReferenceComponent(DockerReference reference)
+ public ContainerImageReferenceComponent(ContainerImageReference reference)
{
}
- public DockerReferenceComponent()
+ public ContainerImageReferenceComponent()
{
/* Reserved for deserialization */
}
@@ -34,13 +34,13 @@ public DockerReferenceComponent()
public string Domain { get; set; }
[JsonIgnore]
- public override ComponentType Type => ComponentType.DockerReference;
+ public override ComponentType Type => ComponentType.ContainerImageReference;
- public DockerReference FullReference
+ public ContainerImageReference FullReference
{
get
{
- return DockerReference.CreateDockerReference(this.Repository, this.Domain, this.Digest, this.Tag);
+ return ContainerImageReference.CreateContainerImageReference(this.Repository, this.Domain, this.Digest, this.Tag);
}
}
diff --git a/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs
index d1d19f3a9..247898f8a 100644
--- a/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs
+++ b/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs
@@ -36,11 +36,11 @@ public DockerfileComponentDetector(
public override string Id { get; } = "DockerReference";
- public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.DockerReference)];
+ public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.ContainerImageReference)];
public override IList SearchPatterns { get; } = ["dockerfile", "dockerfile.*", "*.dockerfile"];
- public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.DockerReference];
+ public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.ContainerImageReference];
public override int Version => 1;
@@ -77,19 +77,19 @@ private Task ParseDockerFileAsync(string fileContents, string fileLocation, ISin
var imageReference = this.ProcessDockerfileConstruct(instruction, dockerfileModel.EscapeChar, stageNameMap);
if (imageReference != null)
{
- singleFileComponentRecorder.RegisterUsage(new DetectedComponent(imageReference.ToTypedDockerReferenceComponent()));
+ singleFileComponentRecorder.RegisterUsage(new DetectedComponent(imageReference.ToTypedContainerImageReferenceComponent()));
}
}
return Task.CompletedTask;
}
- private DockerReference ProcessDockerfileConstruct(DockerfileConstruct construct, char escapeChar, Dictionary stageNameMap)
+ private ContainerImageReference ProcessDockerfileConstruct(DockerfileConstruct construct, char escapeChar, Dictionary stageNameMap)
{
try
{
var instructionKeyword = construct.Type;
- DockerReference baseImage = null;
+ ContainerImageReference baseImage = null;
if (instructionKeyword == ConstructType.Instruction)
{
var constructType = construct.GetType().Name;
@@ -110,12 +110,12 @@ private DockerReference ProcessDockerfileConstruct(DockerfileConstruct construct
}
catch (Exception e)
{
- this.Logger.LogError(e, "Failed to detect a DockerReference component, the component will not be registered.");
+ this.Logger.LogError(e, "Failed to detect a ContainerImageReference component, the component will not be registered.");
return null;
}
}
- private DockerReference ParseFromInstruction(DockerfileConstruct construct, char escapeChar, Dictionary stageNameMap)
+ private ContainerImageReference ParseFromInstruction(DockerfileConstruct construct, char escapeChar, Dictionary stageNameMap)
{
var tokens = construct.Tokens.ToArray();
var resolvedFromStatement = construct.ResolveVariables(escapeChar).TrimEnd();
@@ -148,7 +148,7 @@ private DockerReference ParseFromInstruction(DockerfileConstruct construct, char
return null;
}
- return DockerReferenceUtility.ParseFamiliarName(stageNameReference);
+ return ContainerImageReferenceUtility.ParseFamiliarName(stageNameReference);
}
if (this.HasUnresolvedVariables(reference))
@@ -156,10 +156,10 @@ private DockerReference ParseFromInstruction(DockerfileConstruct construct, char
return null;
}
- return DockerReferenceUtility.ParseFamiliarName(reference);
+ return ContainerImageReferenceUtility.ParseFamiliarName(reference);
}
- private DockerReference ParseCopyInstruction(DockerfileConstruct construct, char escapeChar, Dictionary stageNameMap)
+ private ContainerImageReference ParseCopyInstruction(DockerfileConstruct construct, char escapeChar, Dictionary stageNameMap)
{
var resolvedCopyStatement = construct.ResolveVariables(escapeChar).TrimEnd();
var copyInstruction = (CopyInstruction)construct;
@@ -178,7 +178,7 @@ private DockerReference ParseCopyInstruction(DockerfileConstruct construct, char
}
else
{
- return DockerReferenceUtility.ParseFamiliarName(stageNameReference);
+ return ContainerImageReferenceUtility.ParseFamiliarName(stageNameReference);
}
}
@@ -187,7 +187,7 @@ private DockerReference ParseCopyInstruction(DockerfileConstruct construct, char
return null;
}
- return DockerReferenceUtility.ParseFamiliarName(reference);
+ return ContainerImageReferenceUtility.ParseFamiliarName(reference);
}
private bool HasUnresolvedVariables(string reference)
diff --git a/test/Microsoft.ComponentDetection.Common.Tests/DockerReferenceUtilityTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/ContainerImageReferenceUtilityTests.cs
similarity index 79%
rename from test/Microsoft.ComponentDetection.Common.Tests/DockerReferenceUtilityTests.cs
rename to test/Microsoft.ComponentDetection.Common.Tests/ContainerImageReferenceUtilityTests.cs
index bc4f4f1d4..79f949d6b 100644
--- a/test/Microsoft.ComponentDetection.Common.Tests/DockerReferenceUtilityTests.cs
+++ b/test/Microsoft.ComponentDetection.Common.Tests/ContainerImageReferenceUtilityTests.cs
@@ -9,14 +9,14 @@ namespace Microsoft.ComponentDetection.Common.Tests;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
-public class DockerReferenceUtilityTests
+public class ContainerImageReferenceUtilityTests
{
[TestMethod]
public void ParseQualifiedName_ThrowsReferenceNameEmptyException()
{
var qualifiedName = string.Empty;
- var func = () => DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var func = () => ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
func.Should().Throw();
}
@@ -26,7 +26,7 @@ public void ParseQualifiedName_ThrowsReferenceNameContainsUppercaseException()
{
var qualifiedName = "docker.io/library/Nginx";
- var func = () => DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var func = () => ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
func.Should().Throw();
}
@@ -36,7 +36,7 @@ public void ParseQualifiedName_ThrowsReferenceInvalidFormatException()
{
var qualifiedName = "docker.io/library/nginx:latest:latest";
- var func = () => DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var func = () => ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
func.Should().Throw();
}
@@ -46,7 +46,7 @@ public void ParseQualifiedName_ThrowsReferenceNameTooLongException()
{
var qualifiedName = $"docker.io/library/{"nginx".PadRight(256, 'a')}";
- var func = () => DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var func = () => ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
func.Should().Throw();
}
@@ -56,7 +56,7 @@ public void ParseQualifiedName_CreatesProperTaggedReference()
{
var qualifiedName = "docker.io/library/nginx:latest";
- var result = DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var result = ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -73,7 +73,7 @@ public void ParseQualifiedName_CreatesProperRepositoryReference()
{
var qualifiedName = "docker.io/library/nginx";
- var result = DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var result = ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -89,7 +89,7 @@ public void ParseQualifiedName_ThrowsInvalidOperationIfNoComponent()
{
var qualifiedName = "nginx";
- var func = () => DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var func = () => ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
func.Should().Throw();
}
@@ -100,7 +100,7 @@ public void ParseQualifiedName_CreatesProperCanonicalReference()
var hashTag = $"sha256:{new string('a', 64)}";
var qualifiedName = $"docker.io/library/nginx@{hashTag}";
- var result = DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var result = ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -118,7 +118,7 @@ public void ParseQualifiedName_CreatedProperDigestReference()
var hashTag = $"sha256:{new string('a', 64)}";
var qualifiedName = $"nginx@{hashTag}";
- var result = DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var result = ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -133,7 +133,7 @@ public void ParseQualifiedName_CreatedDualReference()
var hashTag = $"sha256:{new string('a', 64)}";
var qualifiedName = $"docker.io/library/nginx:latest@{hashTag}";
- var result = DockerReferenceUtility.ParseQualifiedName(qualifiedName);
+ var result = ContainerImageReferenceUtility.ParseQualifiedName(qualifiedName);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -151,7 +151,7 @@ public void SplitDockerDomain_AddsDefaultDomain()
{
var name = "library/nginx";
- var result = DockerReferenceUtility.SplitDockerDomain(name);
+ var result = ContainerImageReferenceUtility.SplitDockerDomain(name);
result.Should().NotBeNull();
result.Domain.Should().Be("docker.io");
@@ -163,7 +163,7 @@ public void SplitDockerDomain_ReplacesLegacyDefaultDomain()
{
var name = "index.docker.io/library/nginx";
- var result = DockerReferenceUtility.SplitDockerDomain(name);
+ var result = ContainerImageReferenceUtility.SplitDockerDomain(name);
result.Should().NotBeNull();
result.Domain.Should().Be("docker.io");
@@ -175,7 +175,7 @@ public void SplitDockerDomain_UpdatesRemainderWithOfficialRepoName()
{
var name = "nginx";
- var result = DockerReferenceUtility.SplitDockerDomain(name);
+ var result = ContainerImageReferenceUtility.SplitDockerDomain(name);
result.Should().NotBeNull();
result.Domain.Should().Be("docker.io");
@@ -187,7 +187,7 @@ public void SplitDockerDomain_Works()
{
var name = "docker.io/library/nginx";
- var result = DockerReferenceUtility.SplitDockerDomain(name);
+ var result = ContainerImageReferenceUtility.SplitDockerDomain(name);
result.Should().NotBeNull();
result.Domain.Should().Be("docker.io");
@@ -199,7 +199,7 @@ public void ParseFamiliarName_ThrowsReferenceNameNotCanonicalException()
{
var name = new string('a', 64);
- var func = () => DockerReferenceUtility.ParseFamiliarName(name);
+ var func = () => ContainerImageReferenceUtility.ParseFamiliarName(name);
func.Should().Throw();
}
@@ -209,7 +209,7 @@ public void ParseFamiliarName_HandlesMissingTagSeperator()
{
var name = "docker.io/library/nginx";
- var result = DockerReferenceUtility.ParseFamiliarName(name);
+ var result = ContainerImageReferenceUtility.ParseFamiliarName(name);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -220,7 +220,7 @@ public void ParseFamiliarName_HandlesTag()
{
var name = "docker.io/library/nginx:latest";
- var result = DockerReferenceUtility.ParseFamiliarName(name);
+ var result = ContainerImageReferenceUtility.ParseFamiliarName(name);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -231,7 +231,7 @@ public void ParseFamiliarName_ThrowsReferenceNameContainsUppercaseException()
{
var name = "docker.io/library/Nginx";
- var func = () => DockerReferenceUtility.ParseFamiliarName(name);
+ var func = () => ContainerImageReferenceUtility.ParseFamiliarName(name);
func.Should().Throw();
}
@@ -241,7 +241,7 @@ public void ParseAll_HandlesAnchoredIdentifiers()
{
var name = new string('a', 64);
- var result = DockerReferenceUtility.ParseAll(name);
+ var result = ContainerImageReferenceUtility.ParseAll(name);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -252,7 +252,7 @@ public void ParseAll_HandlesDigests()
{
var name = $"sha256:{new string('a', 64)}";
- var result = DockerReferenceUtility.ParseAll(name);
+ var result = ContainerImageReferenceUtility.ParseAll(name);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
@@ -263,7 +263,7 @@ public void ParseAll_ParsesFamiliarNames()
{
var name = "docker.io/library/nginx";
- var result = DockerReferenceUtility.ParseAll(name);
+ var result = ContainerImageReferenceUtility.ParseAll(name);
result.Should().NotBeNull();
result.Should().BeAssignableTo();
diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs
index 57342f7e7..08754975a 100644
--- a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs
+++ b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs
@@ -2,6 +2,7 @@
namespace Microsoft.ComponentDetection.Contracts.Tests;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using AwesomeAssertions;
@@ -273,8 +274,12 @@ public void TypedComponentMapping_AllMappedTypes_AreTypedComponentSubclasses()
[TestMethod]
public void TypedComponentMapping_AllMappedTypes_AreUnique()
{
- // Ensure no two discriminators map to the same type
- var mappedTypes = TypedComponentMapping.TypeDiscriminatorToType.Values.ToList();
+ // Ensure no two discriminators map to the same type, except for known backward-compatibility aliases
+ var backwardCompatAliases = new HashSet(StringComparer.OrdinalIgnoreCase) { "DockerReference" };
+ var mappedTypes = TypedComponentMapping.TypeDiscriminatorToType
+ .Where(kvp => !backwardCompatAliases.Contains(kvp.Key))
+ .Select(kvp => kvp.Value)
+ .ToList();
var uniqueTypes = mappedTypes.Distinct().ToList();
mappedTypes.Should().HaveCount(uniqueTypes.Count, "Each component type should map to a unique concrete type");