@@ -5,6 +5,7 @@ import * as path from "path";
55
66import { Docker , DockerOptions } from "../docker" ;
77import { ImageName } from "../extractor/image" ;
8+ import { parseImageReference } from "../image-reference" ;
89
910import type { DockerPullResult } from "@snyk/snyk-docker-pull" ;
1011import type {
@@ -265,99 +266,15 @@ async function getImageArchive(
265266 }
266267}
267268
268- function isImagePartOfURL ( targetImage ) : boolean {
269- // Based on the Docker spec, if the image contains a hostname, then the hostname should contain
270- // a `.` or `:` before the first instance of a `/`. ref: https://stackoverflow.com/a/37867949
271- if ( ! targetImage . includes ( "/" ) ) {
272- return false ;
273- }
274-
275- const partBeforeFirstForwardSlash = targetImage . split ( "/" ) [ 0 ] ;
276-
277- return (
278- partBeforeFirstForwardSlash . includes ( "." ) ||
279- partBeforeFirstForwardSlash . includes ( ":" ) ||
280- partBeforeFirstForwardSlash === "localhost"
281- ) ;
282- }
283-
284- function extractHostnameFromTargetImage ( targetImage : string ) : {
285- hostname : string ;
286- remainder : string ;
287- } {
288- // We need to detect if the `targetImage` is part of a URL. If not, the default hostname will be
289- // used (registry-1.docker.io). ref: https://stackoverflow.com/a/37867949
290- const defaultHostname = "registry-1.docker.io" ;
291-
292- if ( ! isImagePartOfURL ( targetImage ) ) {
293- return { hostname : defaultHostname , remainder : targetImage } ;
294- }
295-
296- const dockerFriendlyRegistryHostname = "docker.io/" ;
297- if ( targetImage . startsWith ( dockerFriendlyRegistryHostname ) ) {
298- return {
299- hostname : defaultHostname ,
300- remainder : targetImage . substring ( dockerFriendlyRegistryHostname . length ) ,
301- } ;
302- }
303-
304- const i = targetImage . indexOf ( "/" ) ;
305- return {
306- hostname : targetImage . substring ( 0 , i ) ,
307- remainder : targetImage . substring ( i + 1 ) ,
308- } ;
309- }
310-
311- function extractImageNameAndTag (
312- remainder : string ,
313- targetImage : string ,
314- ) : { imageName : string ; tag : string } {
315- const defaultTag = "latest" ;
316-
317- if ( ! remainder . includes ( "@" ) ) {
318- const [ imageName , tag ] = remainder . split ( ":" ) ;
319-
320- return {
321- imageName : appendDefaultRepoPrefixIfRequired ( imageName , targetImage ) ,
322- tag : tag || defaultTag ,
323- } ;
324- }
325-
326- const [ imageName , tag ] = remainder . split ( "@" ) ;
327-
328- return {
329- imageName : appendDefaultRepoPrefixIfRequired (
330- dropTagIfSHAIsPresent ( imageName ) ,
331- targetImage ,
332- ) ,
333- tag : tag || defaultTag ,
334- } ;
335- }
336-
337- function appendDefaultRepoPrefixIfRequired (
338- imageName : string ,
339- targetImage : string ,
340- ) : string {
341- const defaultRepoPrefix = "library/" ;
342-
343- if ( isImagePartOfURL ( targetImage ) || imageName . includes ( "/" ) ) {
344- return imageName ;
345- }
346-
347- return defaultRepoPrefix + imageName ;
348- }
349-
350- function dropTagIfSHAIsPresent ( imageName : string ) : string {
351- if ( ! imageName . includes ( ":" ) ) {
352- return imageName ;
353- }
354-
355- return imageName . split ( ":" ) [ 0 ] ;
356- }
357-
358269function extractImageDetails ( targetImage : string ) : ImageDetails {
359- const { hostname, remainder } = extractHostnameFromTargetImage ( targetImage ) ;
360- const { imageName, tag } = extractImageNameAndTag ( remainder , targetImage ) ;
270+ const parsed = parseImageReference ( targetImage ) ;
271+ const hostname = parsed . registryForPull ;
272+ const isDockerHub = hostname === "registry-1.docker.io" ;
273+ const imageName =
274+ isDockerHub && ! parsed . repository . includes ( "/" )
275+ ? "library/" + parsed . repository
276+ : parsed . repository ;
277+ const tag = parsed . tailReferenceForPull ;
361278 return { hostname, imageName, tag } ;
362279}
363280
0 commit comments