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 }