@@ -4,6 +4,10 @@ module UriUtils
44 SSH_REGEX = %r{ \A (?:ssh://)? git@ .+? : .+? \. git \z }x
55 GIT_REGEX = %r{ \A git:// .+? : .+? \. git \z }x
66 DOCKER_INDEX_SERVER = 'docker.io' . freeze
7+ DOCKER_PATH_REGEX = %r{\A [a-z0-9_\- \. \/ ]{2,255}\Z }
8+ DOCKER_TAG_REGEX = %r{[a-zA-Z0-9_\- \. ]{1,128}}
9+ DOCKER_DIGEST_REGEX = %r{sha256:[a-z0-9]{64}}
10+ DOCKER_TAG_DIGEST_REGEX = Regexp . new ( "\\ A(#{ DOCKER_TAG_REGEX . source } | (#{ DOCKER_TAG_REGEX . source } @#{ DOCKER_DIGEST_REGEX . source } ) | #{ DOCKER_DIGEST_REGEX . source } )\\ Z" , Regexp ::EXTENDED )
711
812 class InvalidDockerURI < StandardError ; end
913
@@ -62,13 +66,20 @@ def self.parse_docker_uri(docker_uri)
6266 end
6367
6468 path = 'library/' + path if ( official_docker_registry ( name_parts [ 0 ] ) || missing_registry ( name_parts ) ) && path . exclude? ( '/' )
69+ path , tag_digest = parse_docker_tag_or_digest_from_path ( path )
6570
66- path , tag = parse_docker_repository_tag ( path )
71+ raise InvalidDockerURI . new "Invalid image name [#{ path } ]" unless DOCKER_PATH_REGEX =~ path
72+ raise InvalidDockerURI . new "Invalid image tag [#{ tag_digest } ]" if tag_digest && !( DOCKER_TAG_DIGEST_REGEX =~ tag_digest )
6773
68- raise InvalidDockerURI . new "Invalid image name [#{ path } ]" unless %r{\A [a-z0-9_\- \. \/ ]{2,255}\Z } =~ path
69- raise InvalidDockerURI . new "Invalid image tag [#{ tag } ]" if tag && !( /\A (([a-zA-Z0-9_\- \. ]{1,128})|(([a-zA-Z0-9_\- \. ]{0,128})(@sha256:[a-z0-9]{64})))\Z / =~ tag )
74+ # if only sha256 presented, we add hash value as fragment to the uri,
75+ # since the ruby uri parser confuses because of second ':' in uri's path part.
76+ if tag_digest && tag_digest . start_with? ( "sha256:" )
77+ hash_algo , hash_value = tag_digest . split ( ":" )
78+ path = path + "@sha256"
79+ tag_digest = hash_value
80+ end
7081
71- [ host , path , tag ]
82+ [ host , path , tag_digest ]
7283 end
7384
7485 private_class_method def self . official_docker_registry ( host )
@@ -78,13 +89,12 @@ def self.parse_docker_uri(docker_uri)
7889 private_class_method def self . missing_registry ( name_parts )
7990 host = name_parts [ 0 ]
8091 name_parts . length == 1 ||
81- ( host . exclude? ( '.' ) && host . exclude? ( ':' ) && host != 'localhost' )
92+ ( host . exclude? ( '.' ) && host . exclude? ( ':' ) && host != 'localhost' )
8293 end
8394
84- private_class_method def self . parse_docker_repository_tag ( path )
85- path , tag = path . split ( /(?=@)|:/ , 2 )
86-
87- return [ path , tag ] unless tag && tag . include? ( '/' )
95+ private_class_method def self . parse_docker_tag_or_digest_from_path ( path )
96+ path , tag_digest = path . split ( /@|:/ , 2 )
97+ return [ path , tag_digest ] unless tag_digest && tag_digest . include? ( '/' )
8898
8999 [ path , 'latest' ]
90100 end
0 commit comments