mirror of
https://github.com/Infisical/infisical.git
synced 2026-05-02 03:02:03 -04:00
280 lines
7.6 KiB
Go
280 lines
7.6 KiB
Go
// MIT License
|
|
|
|
// Copyright (c) 2019 Zachary Rice
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
package config
|
|
|
|
import (
|
|
_ "embed"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
//go:embed infisical-scan.toml
|
|
var DefaultConfig string
|
|
|
|
// use to keep track of how many configs we can extend
|
|
// yea I know, globals bad
|
|
var extendDepth int
|
|
|
|
const maxExtendDepth = 2
|
|
|
|
const DefaultScanConfigFileName = ".infisical-scan.toml"
|
|
const DefaultScanConfigEnvName = "INFISICAL_SCAN_CONFIG"
|
|
const DefaultInfisicalIgnoreFineName = ".infisicalignore"
|
|
|
|
// ViperConfig is the config struct used by the Viper config package
|
|
// to parse the config file. This struct does not include regular expressions.
|
|
// It is used as an intermediary to convert the Viper config to the Config struct.
|
|
type ViperConfig struct {
|
|
Description string
|
|
Extend Extend
|
|
Rules []struct {
|
|
ID string
|
|
Description string
|
|
Entropy float64
|
|
SecretGroup int
|
|
Regex string
|
|
Keywords []string
|
|
Path string
|
|
Tags []string
|
|
|
|
Allowlist struct {
|
|
RegexTarget string
|
|
Regexes []string
|
|
Paths []string
|
|
Commits []string
|
|
StopWords []string
|
|
}
|
|
}
|
|
Allowlist struct {
|
|
RegexTarget string
|
|
Regexes []string
|
|
Paths []string
|
|
Commits []string
|
|
StopWords []string
|
|
}
|
|
}
|
|
|
|
// Config is a configuration struct that contains rules and an allowlist if present.
|
|
type Config struct {
|
|
Extend Extend
|
|
Path string
|
|
Description string
|
|
Rules map[string]Rule
|
|
Allowlist Allowlist
|
|
Keywords []string
|
|
|
|
// used to keep sarif results consistent
|
|
orderedRules []string
|
|
}
|
|
|
|
// Extend is a struct that allows users to define how they want their
|
|
// configuration extended by other configuration files.
|
|
type Extend struct {
|
|
Path string
|
|
URL string
|
|
UseDefault bool
|
|
}
|
|
|
|
func (vc *ViperConfig) Translate() (Config, error) {
|
|
var (
|
|
keywords []string
|
|
orderedRules []string
|
|
)
|
|
rulesMap := make(map[string]Rule)
|
|
|
|
for _, r := range vc.Rules {
|
|
var allowlistRegexes []*regexp.Regexp
|
|
for _, a := range r.Allowlist.Regexes {
|
|
allowlistRegexes = append(allowlistRegexes, regexp.MustCompile(a))
|
|
}
|
|
var allowlistPaths []*regexp.Regexp
|
|
for _, a := range r.Allowlist.Paths {
|
|
allowlistPaths = append(allowlistPaths, regexp.MustCompile(a))
|
|
}
|
|
|
|
if r.Keywords == nil {
|
|
r.Keywords = []string{}
|
|
} else {
|
|
for _, k := range r.Keywords {
|
|
keywords = append(keywords, strings.ToLower(k))
|
|
}
|
|
}
|
|
|
|
if r.Tags == nil {
|
|
r.Tags = []string{}
|
|
}
|
|
|
|
var configRegex *regexp.Regexp
|
|
var configPathRegex *regexp.Regexp
|
|
if r.Regex == "" {
|
|
configRegex = nil
|
|
} else {
|
|
configRegex = regexp.MustCompile(r.Regex)
|
|
}
|
|
if r.Path == "" {
|
|
configPathRegex = nil
|
|
} else {
|
|
configPathRegex = regexp.MustCompile(r.Path)
|
|
}
|
|
r := Rule{
|
|
Description: r.Description,
|
|
RuleID: r.ID,
|
|
Regex: configRegex,
|
|
Path: configPathRegex,
|
|
SecretGroup: r.SecretGroup,
|
|
Entropy: r.Entropy,
|
|
Tags: r.Tags,
|
|
Keywords: r.Keywords,
|
|
Allowlist: Allowlist{
|
|
RegexTarget: r.Allowlist.RegexTarget,
|
|
Regexes: allowlistRegexes,
|
|
Paths: allowlistPaths,
|
|
Commits: r.Allowlist.Commits,
|
|
StopWords: r.Allowlist.StopWords,
|
|
},
|
|
}
|
|
orderedRules = append(orderedRules, r.RuleID)
|
|
|
|
if r.Regex != nil && r.SecretGroup > r.Regex.NumSubexp() {
|
|
return Config{}, fmt.Errorf("%s invalid regex secret group %d, max regex secret group %d", r.Description, r.SecretGroup, r.Regex.NumSubexp())
|
|
}
|
|
rulesMap[r.RuleID] = r
|
|
}
|
|
var allowlistRegexes []*regexp.Regexp
|
|
for _, a := range vc.Allowlist.Regexes {
|
|
allowlistRegexes = append(allowlistRegexes, regexp.MustCompile(a))
|
|
}
|
|
var allowlistPaths []*regexp.Regexp
|
|
for _, a := range vc.Allowlist.Paths {
|
|
allowlistPaths = append(allowlistPaths, regexp.MustCompile(a))
|
|
}
|
|
c := Config{
|
|
Description: vc.Description,
|
|
Extend: vc.Extend,
|
|
Rules: rulesMap,
|
|
Allowlist: Allowlist{
|
|
RegexTarget: vc.Allowlist.RegexTarget,
|
|
Regexes: allowlistRegexes,
|
|
Paths: allowlistPaths,
|
|
Commits: vc.Allowlist.Commits,
|
|
StopWords: vc.Allowlist.StopWords,
|
|
},
|
|
Keywords: keywords,
|
|
orderedRules: orderedRules,
|
|
}
|
|
|
|
if maxExtendDepth != extendDepth {
|
|
// disallow both usedefault and path from being set
|
|
if c.Extend.Path != "" && c.Extend.UseDefault {
|
|
log.Fatal().Msg("unable to load config due to extend.path and extend.useDefault being set")
|
|
}
|
|
if c.Extend.UseDefault {
|
|
c.extendDefault()
|
|
} else if c.Extend.Path != "" {
|
|
c.extendPath()
|
|
}
|
|
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
func (c *Config) OrderedRules() []Rule {
|
|
var orderedRules []Rule
|
|
for _, id := range c.orderedRules {
|
|
if _, ok := c.Rules[id]; ok {
|
|
orderedRules = append(orderedRules, c.Rules[id])
|
|
}
|
|
}
|
|
return orderedRules
|
|
}
|
|
|
|
func (c *Config) extendDefault() {
|
|
extendDepth++
|
|
viper.SetConfigType("toml")
|
|
if err := viper.ReadConfig(strings.NewReader(DefaultConfig)); err != nil {
|
|
log.Fatal().Msgf("failed to load extended config, err: %s", err)
|
|
return
|
|
}
|
|
defaultViperConfig := ViperConfig{}
|
|
if err := viper.Unmarshal(&defaultViperConfig); err != nil {
|
|
log.Fatal().Msgf("failed to load extended config, err: %s", err)
|
|
return
|
|
}
|
|
cfg, err := defaultViperConfig.Translate()
|
|
if err != nil {
|
|
log.Fatal().Msgf("failed to load extended config, err: %s", err)
|
|
return
|
|
}
|
|
log.Debug().Msg("extending config with default config")
|
|
c.extend(cfg)
|
|
|
|
}
|
|
|
|
func (c *Config) extendPath() {
|
|
extendDepth++
|
|
viper.SetConfigFile(c.Extend.Path)
|
|
if err := viper.ReadInConfig(); err != nil {
|
|
log.Fatal().Msgf("failed to load extended config, err: %s", err)
|
|
return
|
|
}
|
|
extensionViperConfig := ViperConfig{}
|
|
if err := viper.Unmarshal(&extensionViperConfig); err != nil {
|
|
log.Fatal().Msgf("failed to load extended config, err: %s", err)
|
|
return
|
|
}
|
|
cfg, err := extensionViperConfig.Translate()
|
|
if err != nil {
|
|
log.Fatal().Msgf("failed to load extended config, err: %s", err)
|
|
return
|
|
}
|
|
log.Debug().Msgf("extending config with %s", c.Extend.Path)
|
|
c.extend(cfg)
|
|
}
|
|
|
|
func (c *Config) extendURL() {
|
|
// TODO
|
|
}
|
|
|
|
func (c *Config) extend(extensionConfig Config) {
|
|
for ruleID, rule := range extensionConfig.Rules {
|
|
if _, ok := c.Rules[ruleID]; !ok {
|
|
log.Trace().Msgf("adding %s to base config", ruleID)
|
|
c.Rules[ruleID] = rule
|
|
c.Keywords = append(c.Keywords, rule.Keywords...)
|
|
}
|
|
}
|
|
|
|
// append allowlists, not attempting to merge
|
|
c.Allowlist.Commits = append(c.Allowlist.Commits,
|
|
extensionConfig.Allowlist.Commits...)
|
|
c.Allowlist.Paths = append(c.Allowlist.Paths,
|
|
extensionConfig.Allowlist.Paths...)
|
|
c.Allowlist.Regexes = append(c.Allowlist.Regexes,
|
|
extensionConfig.Allowlist.Regexes...)
|
|
}
|