Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ launchSettings.json

# Dev nupkgs
dev-source
.nuget/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

for some reason copilot kept trying to check in .nuget/nuget.exe so this removes that.

2 changes: 1 addition & 1 deletion docs/detectors/dockerfile.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions docs/schema/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
"Conda",
"Spdx",
"Vcpkg",
"ContainerImageReference",
"DockerReference",
"Conan",
"Swift",
Expand Down Expand Up @@ -424,6 +425,7 @@
"Conda",
"Spdx",
"Vcpkg",
"ContainerImageReference",
"DockerReference",
"Conan",
"Swift",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand All @@ -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";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ 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;
private const string DEFAULTDOMAIN = "docker.io";
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))
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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("(?:[._]|__|[-]*)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) },
Expand Down
Loading