127 lines
3.4 KiB
Go
127 lines
3.4 KiB
Go
|
package internal
|
||
|
|
||
|
import (
|
||
|
"github.com/pkg/errors"
|
||
|
"path/filepath"
|
||
|
"regexp"
|
||
|
"runtime"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// annotation spex from https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
|
||
|
const (
|
||
|
separator = `(?:[-._:@+]|--)`
|
||
|
alphanum = `(?:[A-Za-z0-9]+)`
|
||
|
component = `(?:` + alphanum + `(?:` + separator + alphanum + `)*)`
|
||
|
)
|
||
|
|
||
|
var refRegexp = regexp.MustCompile(`^` + component + `(?:/` + component + `)*$`)
|
||
|
var windowsRefRegexp = regexp.MustCompile(`^([a-zA-Z]:\\.+?):(.*)$`)
|
||
|
|
||
|
// ValidateImageName returns nil if the image name is empty or matches the open-containers image name specs.
|
||
|
// In any other case an error is returned.
|
||
|
func ValidateImageName(image string) error {
|
||
|
if len(image) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
var err error
|
||
|
if !refRegexp.MatchString(image) {
|
||
|
err = errors.Errorf("Invalid image %s", image)
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// SplitPathAndImage tries to split the provided OCI reference into the OCI path and image.
|
||
|
// Neither path nor image parts are validated at this stage.
|
||
|
func SplitPathAndImage(reference string) (string, string) {
|
||
|
if runtime.GOOS == "windows" {
|
||
|
return splitPathAndImageWindows(reference)
|
||
|
}
|
||
|
return splitPathAndImageNonWindows(reference)
|
||
|
}
|
||
|
|
||
|
func splitPathAndImageWindows(reference string) (string, string) {
|
||
|
groups := windowsRefRegexp.FindStringSubmatch(reference)
|
||
|
// nil group means no match
|
||
|
if groups == nil {
|
||
|
return reference, ""
|
||
|
}
|
||
|
|
||
|
// we expect three elements. First one full match, second the capture group for the path and
|
||
|
// the third the capture group for the image
|
||
|
if len(groups) != 3 {
|
||
|
return reference, ""
|
||
|
}
|
||
|
return groups[1], groups[2]
|
||
|
}
|
||
|
|
||
|
func splitPathAndImageNonWindows(reference string) (string, string) {
|
||
|
sep := strings.SplitN(reference, ":", 2)
|
||
|
path := sep[0]
|
||
|
|
||
|
var image string
|
||
|
if len(sep) == 2 {
|
||
|
image = sep[1]
|
||
|
}
|
||
|
return path, image
|
||
|
}
|
||
|
|
||
|
// ValidateOCIPath takes the OCI path and validates it.
|
||
|
func ValidateOCIPath(path string) error {
|
||
|
if runtime.GOOS == "windows" {
|
||
|
// On Windows we must allow for a ':' as part of the path
|
||
|
if strings.Count(path, ":") > 1 {
|
||
|
return errors.Errorf("Invalid OCI reference: path %s contains more than one colon", path)
|
||
|
}
|
||
|
} else {
|
||
|
if strings.Contains(path, ":") {
|
||
|
return errors.Errorf("Invalid OCI reference: path %s contains a colon", path)
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// ValidateScope validates a policy configuration scope for an OCI transport.
|
||
|
func ValidateScope(scope string) error {
|
||
|
var err error
|
||
|
if runtime.GOOS == "windows" {
|
||
|
err = validateScopeWindows(scope)
|
||
|
} else {
|
||
|
err = validateScopeNonWindows(scope)
|
||
|
}
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
cleaned := filepath.Clean(scope)
|
||
|
if cleaned != scope {
|
||
|
return errors.Errorf(`Invalid scope %s: Uses non-canonical path format, perhaps try with path %s`, scope, cleaned)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func validateScopeWindows(scope string) error {
|
||
|
matched, _ := regexp.Match(`^[a-zA-Z]:\\`, []byte(scope))
|
||
|
if !matched {
|
||
|
return errors.Errorf("Invalid scope '%s'. Must be an absolute path", scope)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func validateScopeNonWindows(scope string) error {
|
||
|
if !strings.HasPrefix(scope, "/") {
|
||
|
return errors.Errorf("Invalid scope %s: must be an absolute path", scope)
|
||
|
}
|
||
|
|
||
|
// Refuse also "/", otherwise "/" and "" would have the same semantics,
|
||
|
// and "" could be unexpectedly shadowed by the "/" entry.
|
||
|
if scope == "/" {
|
||
|
return errors.New(`Invalid scope "/": Use the generic default scope ""`)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|