diff --git a/Sources/ContainerizationOCI/Reference.swift b/Sources/ContainerizationOCI/Reference.swift index bd56481c..af5d25e9 100644 --- a/Sources/ContainerizationOCI/Reference.swift +++ b/Sources/ContainerizationOCI/Reference.swift @@ -17,8 +17,13 @@ import ContainerizationError import Foundation -private let referenceTotalLengthMax = 255 -private let nameTotalLengthMax = 127 +// nameTotalLengthMax matches the OCI distribution spec which allows up to 255 bytes for the +// repository name component (domain + "/" + path). +private let nameTotalLengthMax = 255 +// referenceTotalLengthMax is the upper bound for the full reference string: max name (255) + +// separator (1) + max tag length (128) = 384. +private let tagLengthMax = 128 +private let referenceTotalLengthMax = nameTotalLengthMax + 1 + tagLengthMax private let legacyDockerRegistryHost = "docker.io" private let dockerRegistryHost = "registry-1.docker.io" private let defaultDockerRegistryRepo = "library" diff --git a/Tests/ContainerizationOCITests/ReferenceTests.swift b/Tests/ContainerizationOCITests/ReferenceTests.swift index 7650092e..6a744bbc 100644 --- a/Tests/ContainerizationOCITests/ReferenceTests.swift +++ b/Tests/ContainerizationOCITests/ReferenceTests.swift @@ -56,6 +56,16 @@ struct ReferenceParseTests { digest: "sha256:\(String(repeating: "abcd", count: 16))"), ReferenceParseTestCase(input: "192.168.1.1:5544/local/swift:6.0", domain: "192.168.1.1:5544", path: "local/swift", tag: "6.0"), ReferenceParseTestCase(input: "[abc12::4]:5683/swift", domain: "[abc12::4]:5683", path: "swift"), + // Verify names longer than 127 characters are accepted (OCI spec allows up to 255). + ReferenceParseTestCase( + input: "reg.io/\(String(repeating: "a", count: 121))", + domain: "reg.io", + path: String(repeating: "a", count: 121)), + // Verify a name of exactly 255 characters (the OCI spec maximum) is accepted. + ReferenceParseTestCase( + input: "registry.example.com/\(String(repeating: "a", count: 234))", + domain: "registry.example.com", + path: String(repeating: "a", count: 234)), ]) func validReferenceParse(testCase: ReferenceParseTestCase) async throws { #expect(throws: Never.self) { @@ -81,6 +91,8 @@ struct ReferenceParseTests { "[abc12::4]:abc12::4", "[2001:db8:3:4::192.0.2.33]:5000/debian", "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a", + // A name of 256 characters exceeds the OCI spec limit of 255 and must be rejected. + "registry.example.com/\(String(repeating: "a", count: 235))", ]) func invalidReferenceParse(input: String) async throws { #expect(throws: ContainerizationError.self) {