github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/validator/rules/relativepath.go (about)

     1  package rules
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"regexp"
     7  	"strings"
     8  )
     9  
    10  type relativePathRule struct {
    11  	volumes map[string]interface{}
    12  	service string
    13  }
    14  
    15  func NewRelativePathRule() Rule {
    16  	return &relativePathRule{
    17  		volumes: map[string]interface{}{},
    18  	}
    19  }
    20  
    21  func (s *relativePathRule) Collect(parent string, key string, value interface{}) {
    22  	if parent == "volumes" {
    23  		s.volumes[key] = value
    24  	}
    25  }
    26  
    27  func (s *relativePathRule) Accept(parent string, key string) bool {
    28  	if parent == "services" {
    29  		s.service = key
    30  	}
    31  	return regexp.MustCompile("services.(.*).volumes").MatchString(parent + "." + key)
    32  }
    33  
    34  func (s *relativePathRule) Validate(value interface{}) []error {
    35  	if m, ok := value.(map[string]interface{}); ok {
    36  		src, ok := m["source"]
    37  		if !ok {
    38  			return []error{fmt.Errorf("invalid volume in service %q", s.service)}
    39  		}
    40  		_, volumeExists := s.volumes[src.(string)]
    41  		if !filepath.IsAbs(src.(string)) && !volumeExists {
    42  			return []error{fmt.Errorf("can't use relative path as volume source (%q) in service %q", src, s.service)}
    43  		}
    44  	}
    45  
    46  	if m, ok := value.([]interface{}); ok {
    47  		errs := []error{}
    48  		for _, p := range m {
    49  			str, ok := p.(string)
    50  			if !ok {
    51  				errs = append(errs, fmt.Errorf("invalid volume in service %q", s.service))
    52  				continue
    53  			}
    54  
    55  			parts := strings.Split(str, ":")
    56  			if len(parts) <= 1 {
    57  				errs = append(errs, fmt.Errorf("invalid volume definition (%q) in service %q", str, s.service))
    58  				continue
    59  			}
    60  
    61  			volumeName := parts[0]
    62  			_, volumeExists := s.volumes[volumeName]
    63  			if !filepath.IsAbs(volumeName) && !volumeExists {
    64  				errs = append(errs, fmt.Errorf("can't use relative path as volume source (%q) in service %q", str, s.service))
    65  				continue
    66  			}
    67  		}
    68  
    69  		if len(errs) > 0 {
    70  			return errs
    71  		}
    72  	}
    73  	return nil
    74  }