github.com/apptainer/singularity@v3.1.1+incompatible/pkg/client/shub/util.go (about)

     1  // Copyright (c) 2018, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package client
     7  
     8  import (
     9  	"errors"
    10  	"regexp"
    11  	"strings"
    12  )
    13  
    14  // isShubPullRef returns true if the provided string is a valid Shub
    15  // reference for a pull operation.
    16  func isShubPullRef(shubRef string) bool {
    17  	// define regex for each URI component
    18  	registryRegexp := `([-.a-zA-Z0-9/]{1,64}\/)?`           // target is very open, outside registry
    19  	nameRegexp := `([-a-zA-Z0-9]{1,39}\/)`                  // target valid github usernames
    20  	containerRegexp := `([-_.a-zA-Z0-9]{1,64})`             // target valid github repo names
    21  	tagRegexp := `(:[-_.a-zA-Z0-9]{1,64})?`                 // target is very open, file extensions or branch names
    22  	digestRegexp := `((\@[a-f0-9]{32})|(\@[a-f0-9]{40}))?$` // target file md5 has, git commit hash, git branch
    23  
    24  	// expression is anchored
    25  	shubRegex, err := regexp.Compile(`^(shub://)` + registryRegexp + nameRegexp + containerRegexp + tagRegexp + digestRegexp + `$`)
    26  	if err != nil {
    27  		return false
    28  	}
    29  
    30  	found := shubRegex.FindString(shubRef)
    31  
    32  	// sanity check
    33  	// if found string is not equal to the input, input isn't a valid URI
    34  	if strings.Compare(shubRef, found) != 0 {
    35  		return false
    36  	}
    37  
    38  	return true
    39  }
    40  
    41  // shubParseReference accepts a valid Shub reference string and parses its content
    42  // It will return an error if the given URI is not valid,
    43  // otherwise it will parse the contents into a ShubURI struct
    44  func shubParseReference(src string) (uri ShubURI, err error) {
    45  	ShubRef := strings.TrimPrefix(src, "shub://")
    46  	refParts := strings.Split(ShubRef, "/")
    47  
    48  	if l := len(refParts); l > 2 {
    49  		// more than two pieces indicates a custom registry
    50  		uri.registry = strings.Join(refParts[:l-2], "") + shubAPIRoute
    51  		uri.user = refParts[l-2]
    52  		src = refParts[l-1]
    53  	} else if l == 2 {
    54  		// two pieces means default registry
    55  		uri.registry = defaultRegistry + shubAPIRoute
    56  		uri.user = refParts[l-2]
    57  		src = refParts[l-1]
    58  	} else if l < 2 {
    59  		return ShubURI{}, errors.New("Not a valid Shub reference")
    60  	}
    61  
    62  	// look for an @ and split if it exists
    63  	if strings.Contains(src, `@`) {
    64  		refParts = strings.Split(src, `@`)
    65  		uri.digest = `@` + refParts[1]
    66  		src = refParts[0]
    67  	}
    68  
    69  	// look for a : and split if it exists
    70  	if strings.Contains(src, `:`) {
    71  		refParts = strings.Split(src, `:`)
    72  		uri.tag = `:` + refParts[1]
    73  		src = refParts[0]
    74  	}
    75  
    76  	// container name is left over after other parts are split from it
    77  	uri.container = src
    78  
    79  	if uri.tag == "" && uri.digest == "" {
    80  		uri.tag = ":latest"
    81  	}
    82  
    83  	return uri, nil
    84  }