Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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) },
Comment thread
jpinz marked this conversation as resolved.
{ "DockerReference", typeof(ContainerImageReferenceComponent) },
{ nameof(ComponentType.Vcpkg), typeof(VcpkgComponent) },
{ nameof(ComponentType.Spdx), typeof(SpdxComponent) },
{ nameof(ComponentType.DotNet), typeof(DotNetComponent) },
Expand Down
Loading