/vendor/github.com/containers/image/v5/oci/internal/oci_util.go

https://gitlab.com/unofficial-mirrors/openshift-source-to-image · Go · 126 lines · 94 code · 19 blank · 13 comment · 27 complexity · 0011d657070af175258538e8607f93b7 MD5 · raw file

  1. package internal
  2. import (
  3. "github.com/pkg/errors"
  4. "path/filepath"
  5. "regexp"
  6. "runtime"
  7. "strings"
  8. )
  9. // annotation spex from https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
  10. const (
  11. separator = `(?:[-._:@+]|--)`
  12. alphanum = `(?:[A-Za-z0-9]+)`
  13. component = `(?:` + alphanum + `(?:` + separator + alphanum + `)*)`
  14. )
  15. var refRegexp = regexp.MustCompile(`^` + component + `(?:/` + component + `)*$`)
  16. var windowsRefRegexp = regexp.MustCompile(`^([a-zA-Z]:\\.+?):(.*)$`)
  17. // ValidateImageName returns nil if the image name is empty or matches the open-containers image name specs.
  18. // In any other case an error is returned.
  19. func ValidateImageName(image string) error {
  20. if len(image) == 0 {
  21. return nil
  22. }
  23. var err error
  24. if !refRegexp.MatchString(image) {
  25. err = errors.Errorf("Invalid image %s", image)
  26. }
  27. return err
  28. }
  29. // SplitPathAndImage tries to split the provided OCI reference into the OCI path and image.
  30. // Neither path nor image parts are validated at this stage.
  31. func SplitPathAndImage(reference string) (string, string) {
  32. if runtime.GOOS == "windows" {
  33. return splitPathAndImageWindows(reference)
  34. }
  35. return splitPathAndImageNonWindows(reference)
  36. }
  37. func splitPathAndImageWindows(reference string) (string, string) {
  38. groups := windowsRefRegexp.FindStringSubmatch(reference)
  39. // nil group means no match
  40. if groups == nil {
  41. return reference, ""
  42. }
  43. // we expect three elements. First one full match, second the capture group for the path and
  44. // the third the capture group for the image
  45. if len(groups) != 3 {
  46. return reference, ""
  47. }
  48. return groups[1], groups[2]
  49. }
  50. func splitPathAndImageNonWindows(reference string) (string, string) {
  51. sep := strings.SplitN(reference, ":", 2)
  52. path := sep[0]
  53. var image string
  54. if len(sep) == 2 {
  55. image = sep[1]
  56. }
  57. return path, image
  58. }
  59. // ValidateOCIPath takes the OCI path and validates it.
  60. func ValidateOCIPath(path string) error {
  61. if runtime.GOOS == "windows" {
  62. // On Windows we must allow for a ':' as part of the path
  63. if strings.Count(path, ":") > 1 {
  64. return errors.Errorf("Invalid OCI reference: path %s contains more than one colon", path)
  65. }
  66. } else {
  67. if strings.Contains(path, ":") {
  68. return errors.Errorf("Invalid OCI reference: path %s contains a colon", path)
  69. }
  70. }
  71. return nil
  72. }
  73. // ValidateScope validates a policy configuration scope for an OCI transport.
  74. func ValidateScope(scope string) error {
  75. var err error
  76. if runtime.GOOS == "windows" {
  77. err = validateScopeWindows(scope)
  78. } else {
  79. err = validateScopeNonWindows(scope)
  80. }
  81. if err != nil {
  82. return err
  83. }
  84. cleaned := filepath.Clean(scope)
  85. if cleaned != scope {
  86. return errors.Errorf(`Invalid scope %s: Uses non-canonical path format, perhaps try with path %s`, scope, cleaned)
  87. }
  88. return nil
  89. }
  90. func validateScopeWindows(scope string) error {
  91. matched, _ := regexp.Match(`^[a-zA-Z]:\\`, []byte(scope))
  92. if !matched {
  93. return errors.Errorf("Invalid scope '%s'. Must be an absolute path", scope)
  94. }
  95. return nil
  96. }
  97. func validateScopeNonWindows(scope string) error {
  98. if !strings.HasPrefix(scope, "/") {
  99. return errors.Errorf("Invalid scope %s: must be an absolute path", scope)
  100. }
  101. // Refuse also "/", otherwise "/" and "" would have the same semantics,
  102. // and "" could be unexpectedly shadowed by the "/" entry.
  103. if scope == "/" {
  104. return errors.New(`Invalid scope "/": Use the generic default scope ""`)
  105. }
  106. return nil
  107. }