github.com/yogeshkumararora/slsa-github-generator@v1.10.1-0.20240520161934-11278bd5afb4/internal/builders/go/pkg/config.go (about) 1 // Copyright 2022 SLSA Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pkg 16 17 import ( 18 "errors" 19 "fmt" 20 "os" 21 "path/filepath" 22 "strings" 23 24 "gopkg.in/yaml.v3" 25 26 "github.com/yogeshkumararora/slsa-github-generator/internal/utils" 27 ) 28 29 var supportedVersions = map[int]bool{ 30 1: true, 31 } 32 33 type goReleaserConfigFile struct { 34 Main *string `yaml:"main"` 35 Dir *string `yaml:"dir"` 36 Goos string `yaml:"goos"` 37 Goarch string `yaml:"goarch"` 38 Binary string `yaml:"binary"` 39 Env []string `yaml:"env"` 40 Flags []string `yaml:"flags"` 41 Ldflags []string `yaml:"ldflags"` 42 Version int `yaml:"version"` 43 } 44 45 // GoReleaserConfig tracks configuration for goreleaser. 46 type GoReleaserConfig struct { 47 Env map[string]string 48 Main *string 49 Dir *string 50 Goos string 51 Goarch string 52 Binary string 53 Flags []string 54 Ldflags []string 55 } 56 57 var ( 58 // ErrUnsupportedVersion indicates an unsupported Go builder version. 59 ErrUnsupportedVersion = errors.New("unsupported version") 60 61 // ErrInvalidDirectory indicates an invalid directory. 62 ErrInvalidDirectory = errors.New("invalid directory") 63 64 // ErrInvalidEnvironmentVariable indicates an invalid environment variable. 65 ErrInvalidEnvironmentVariable = errors.New("invalid environment variable") 66 ) 67 68 func configFromString(b []byte) (*GoReleaserConfig, error) { 69 var cf goReleaserConfigFile 70 if err := yaml.Unmarshal(b, &cf); err != nil { 71 return nil, fmt.Errorf("yaml.Unmarshal: %w", err) 72 } 73 74 return fromConfig(&cf) 75 } 76 77 // ConfigFromFile reads the file located at path and builds a GoReleaserConfig 78 // from it. 79 func ConfigFromFile(path string) (*GoReleaserConfig, error) { 80 if err := validatePath(path); err != nil { 81 return nil, fmt.Errorf("validate path: %q: %w", path, err) 82 } 83 84 cfg, err := os.ReadFile(filepath.Clean(path)) 85 if err != nil { 86 return nil, fmt.Errorf("%q: os.ReadFile: %w", path, err) 87 } 88 89 c, err := configFromString(cfg) 90 if err != nil { 91 return nil, fmt.Errorf("configfromstring: %q: %w", path, err) 92 } 93 return c, nil 94 } 95 96 func fromConfig(cf *goReleaserConfigFile) (*GoReleaserConfig, error) { 97 if err := validateVersion(cf); err != nil { 98 return nil, err 99 } 100 101 if err := validateMain(cf); err != nil { 102 return nil, err 103 } 104 105 if err := validateDir(cf); err != nil { 106 return nil, err 107 } 108 109 cfg := GoReleaserConfig{ 110 Goos: cf.Goos, 111 Goarch: cf.Goarch, 112 Flags: cf.Flags, 113 Ldflags: cf.Ldflags, 114 Binary: cf.Binary, 115 Main: cf.Main, 116 Dir: cf.Dir, 117 } 118 119 if err := cfg.setEnvs(cf); err != nil { 120 return nil, err 121 } 122 123 return &cfg, nil 124 } 125 126 func validatePath(path string) error { 127 err := utils.PathIsUnderCurrentDirectory(path) 128 if err != nil { 129 return convertPathError(err, "PathIsUnderCurrentDirectory") 130 } 131 return nil 132 } 133 134 func validateDir(cf *goReleaserConfigFile) error { 135 if cf.Dir == nil { 136 return nil 137 } 138 return validatePath(*cf.Dir) 139 } 140 141 func validateMain(cf *goReleaserConfigFile) error { 142 if cf.Main == nil { 143 return nil 144 } 145 146 // Validate the main path is under the current directory. 147 if err := utils.PathIsUnderCurrentDirectory(*cf.Main); err != nil { 148 return convertPathError(err, "PathIsUnderCurrentDirectory") 149 } 150 return nil 151 } 152 153 func convertPathError(e error, msg string) error { 154 if e != nil { 155 if errors.Is(e, utils.ErrInternal) || 156 errors.Is(e, utils.ErrInvalidPath) { 157 return fmt.Errorf("%w: %v", ErrInvalidDirectory, e) 158 } 159 return fmt.Errorf("%s: %w", msg, e) 160 } 161 return e 162 } 163 164 func validateVersion(cf *goReleaserConfigFile) error { 165 _, exists := supportedVersions[cf.Version] 166 if !exists { 167 return fmt.Errorf("%w: '%d'", ErrUnsupportedVersion, cf.Version) 168 } 169 170 return nil 171 } 172 173 func (r *GoReleaserConfig) setEnvs(cf *goReleaserConfigFile) error { 174 m := make(map[string]string) 175 for _, e := range cf.Env { 176 name, value, present := strings.Cut(e, "=") 177 if !present { 178 return fmt.Errorf("%w: '%s' contains no '='", ErrInvalidEnvironmentVariable, e) 179 } 180 m[name] = value 181 } 182 183 if len(m) > 0 { 184 r.Env = m 185 } 186 187 return nil 188 }