github.com/google/go-safeweb@v0.0.0-20231219055052-64d8cfc90fbb/cmd/bancheck/config/config.go (about)

     1  // Copyright 2020 Google LLC
     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  //	https://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 config
    16  
    17  import (
    18  	"encoding/json"
    19  	"errors"
    20  	"os"
    21  )
    22  
    23  // Config represents a configuration passed to the linter.
    24  type Config struct {
    25  	Imports   []BannedAPI `json:"imports"`
    26  	Functions []BannedAPI `json:"functions"`
    27  }
    28  
    29  // BannedAPI represents an identifier (e.g. import, function call) that should not be used.
    30  type BannedAPI struct {
    31  	Name       string      `json:"name"` // fully qualified identifier name
    32  	Msg        string      `json:"msg"`  // additional information e.g. rationale for banning
    33  	Exemptions []Exemption `json:"exemptions"`
    34  }
    35  
    36  // Exemption represents a location that should be exempted from checking for banned APIs.
    37  type Exemption struct {
    38  	Justification string `json:"justification"`
    39  	AllowedPkg    string `json:"allowedPkg"` // Uses Go RegExp https://golang.org/pkg/regexp/syntax
    40  }
    41  
    42  // ReadConfigs reads banned APIs from all files.
    43  func ReadConfigs(files []string) (*Config, error) {
    44  	var imports []BannedAPI
    45  	var fns []BannedAPI
    46  
    47  	for _, file := range files {
    48  		config, err := readCfg(file)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  
    53  		imports = append(imports, config.Imports...)
    54  		fns = append(fns, config.Functions...)
    55  	}
    56  
    57  	return &Config{Imports: imports, Functions: fns}, nil
    58  }
    59  
    60  func readCfg(filename string) (*Config, error) {
    61  	f, err := openFile(filename)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	defer f.Close()
    66  
    67  	return decodeCfg(f)
    68  }
    69  
    70  func openFile(filename string) (*os.File, error) {
    71  	info, err := os.Stat(filename)
    72  	if os.IsNotExist(err) {
    73  		return nil, errors.New("file does not exist")
    74  	}
    75  	if info.IsDir() {
    76  		return nil, errors.New("file is a directory")
    77  	}
    78  
    79  	return os.Open(filename)
    80  }
    81  
    82  func decodeCfg(f *os.File) (*Config, error) {
    83  	var cfg Config
    84  	err := json.NewDecoder(f).Decode(&cfg)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	return &cfg, nil
    90  }