diff --git a/Sources/ContainerResource/Image/ImageResource.swift b/Sources/ContainerResource/Image/ImageResource.swift index b1f27f8c5..820ea5222 100644 --- a/Sources/ContainerResource/Image/ImageResource.swift +++ b/Sources/ContainerResource/Image/ImageResource.swift @@ -69,8 +69,14 @@ public struct ImageResource: ManagedResource { // MARK: ManagedResource - /// The unique identifier for this image. Identical to the image's index digest. - public var id: String { configuration.descriptor.digest } + /// The scheme-specific value of `configuration.descriptor.digest` (the hex portion + /// after the algorithm prefix). The fully-qualified digest — needed for content-store + /// lookups and XPC transport — is always recoverable as `configuration.descriptor.digest`. + public var id: String { + let digest = configuration.descriptor.digest + guard let colonIndex = digest.firstIndex(of: ":") else { return digest } + return String(digest[digest.index(after: colonIndex)...]) + } /// The user-facing reference (`name:tag`) for this image. public var name: String { configuration.name } diff --git a/Sources/Services/ContainerAPIService/Client/Utility.swift b/Sources/Services/ContainerAPIService/Client/Utility.swift index f405cf6d4..bfea2bbc0 100644 --- a/Sources/Services/ContainerAPIService/Client/Utility.swift +++ b/Sources/Services/ContainerAPIService/Client/Utility.swift @@ -44,12 +44,11 @@ public struct Utility { } public static func trimDigest(digest: String) -> String { - var digest = digest - digest.trimPrefix("sha256:") - if digest.count > 24 { - digest = String(digest.prefix(24)) + "..." + var hex = digest + if let colonIndex = digest.firstIndex(of: ":") { + hex = String(digest[digest.index(after: colonIndex)...]) } - return digest + return String(hex.prefix(12)) } public static func validEntityName(_ name: String) throws { diff --git a/Tests/ContainerAPIClientTests/UtilityTests.swift b/Tests/ContainerAPIClientTests/UtilityTests.swift index bc48df975..3a9b3a495 100644 --- a/Tests/ContainerAPIClientTests/UtilityTests.swift +++ b/Tests/ContainerAPIClientTests/UtilityTests.swift @@ -90,6 +90,29 @@ struct UtilityTests { } } + @Test("Trim fully-qualified digest strips scheme and truncates to 12 chars") + func testTrimDigestFullyQualified() { + let hex = "0be69a25c33692845efb1e93f4254f28505a330896376bf8" + #expect(Utility.trimDigest(digest: "sha256:\(hex)") == String(hex.prefix(12))) + } + + @Test("Trim digest with unknown scheme strips scheme prefix") + func testTrimDigestUnknownScheme() { + let hex = "abcdef123456789012345678" + #expect(Utility.trimDigest(digest: "blake3:\(hex)") == String(hex.prefix(12))) + } + + @Test("Trim digest with no scheme truncates directly") + func testTrimDigestNoScheme() { + let hex = "abcdef1234567890" + #expect(Utility.trimDigest(digest: hex) == String(hex.prefix(12))) + } + + @Test("Trim digest shorter than 12 chars returns value unchanged") + func testTrimDigestShort() { + #expect(Utility.trimDigest(digest: "sha256:abc") == "abc") + } + @Test func testPublishPortParser() throws { let ports = try Parser.publishPorts([ diff --git a/docs/tutorials/start-here.md b/docs/tutorials/start-here.md index 041b0079d..933b55329 100644 --- a/docs/tutorials/start-here.md +++ b/docs/tutorials/start-here.md @@ -163,8 +163,8 @@ After the build completes, list the images. You should see both the base image a
% container image list NAME TAG DIGEST -python alpine b4d299311845147e7e47c970... -web-test latest 25b99501f174803e21c58f9c... +python alpine b4d299311845 +web-test latest 25b99501f174 %