-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
options.go
170 lines (149 loc) Β· 5.68 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package gitleaks
import (
"fmt"
"net"
"net/url"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"time"
"github.com/jessevdk/go-flags"
log "github.com/sirupsen/logrus"
)
// Options for gitleaks
type Options struct {
// remote target options
Repo string `short:"r" long:"repo" description:"Repo url to audit"`
GithubUser string `long:"github-user" description:"Github user to audit"`
GithubOrg string `long:"github-org" description:"Github organization to audit"`
GithubURL string `long:"github-url" default:"https://api.github.com/" description:"GitHub API Base URL, use for GitHub Enterprise. Example: https://github.example.com/api/v3/"`
GithubPR string `long:"github-pr" description:"Github PR url to audit. This does not clone the repo. GITHUB_TOKEN must be set"`
GitLabUser string `long:"gitlab-user" description:"GitLab user ID to audit"`
GitLabOrg string `long:"gitlab-org" description:"GitLab group ID to audit"`
CommitStop string `long:"commit-stop" description:"sha of commit to stop at"`
Commit string `long:"commit" description:"sha of commit to audit"`
Depth int64 `long:"depth" description:"maximum commit depth"`
// local target option
RepoPath string `long:"repo-path" description:"Path to repo"`
OwnerPath string `long:"owner-path" description:"Path to owner directory (repos discovered)"`
// Process options
Threads int `long:"threads" description:"Maximum number of threads gitleaks spawns"`
Disk bool `long:"disk" description:"Clones repo(s) to disk"`
SingleSearch string `long:"single-search" description:"single regular expression to search for"`
ConfigPath string `long:"config" description:"path to gitleaks config"`
SSHKey string `long:"ssh-key" description:"path to ssh key"`
ExcludeForks bool `long:"exclude-forks" description:"exclude forks for organization/user audits"`
Entropy float64 `long:"entropy" short:"e" description:"Include entropy checks during audit. Entropy scale: 0.0(no entropy) - 8.0(max entropy)"`
NoiseReduction bool `long:"noise-reduction" description:"Reduce the number of finds when entropy checks are enabled"`
RepoConfig bool `long:"repo-config" description:"Load config from target repo. Config file must be \".gitleaks.toml\""`
Branch string `long:"branch" description:"Branch to audit"`
// TODO: IncludeMessages string `long:"messages" description:"include commit messages in audit"`
// Output options
Log string `short:"l" long:"log" description:"log level"`
Verbose bool `short:"v" long:"verbose" description:"Show verbose output from gitleaks audit"`
Report string `long:"report" description:"path to write report file. Needs to be csv or json"`
Redact bool `long:"redact" description:"redact secrets from log messages and report"`
Version bool `long:"version" description:"version number"`
SampleConfig bool `long:"sample-config" description:"prints a sample config file"`
}
// ParseOpts parses the options
func ParseOpts() *Options {
var opts Options
parser := flags.NewParser(&opts, flags.Default)
_, err := parser.Parse()
if err != nil {
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
os.Exit(0)
}
}
if len(os.Args) == 1 {
// TODO: this will be a feature, check locally
parser.WriteHelp(os.Stdout)
os.Exit(0)
}
if opts.Version {
fmt.Println(version)
os.Exit(0)
}
if opts.SampleConfig {
fmt.Println(defaultConfig)
os.Exit(0)
}
opts.setLogs()
err = opts.guard()
if err != nil {
log.Fatal(err)
}
return &opts
}
// optsGuard prevents invalid options
func (opts *Options) guard() error {
var err error
if opts.GithubOrg != "" && opts.GithubUser != "" {
return fmt.Errorf("github user and organization set")
} else if opts.GithubOrg != "" && opts.OwnerPath != "" {
return fmt.Errorf("github organization set and local owner path")
} else if opts.GithubUser != "" && opts.OwnerPath != "" {
return fmt.Errorf("github user set and local owner path")
}
if opts.Threads > runtime.GOMAXPROCS(0) {
return fmt.Errorf("%d available threads", runtime.GOMAXPROCS(0))
}
// do the URL Parse and error checking here, so we can skip it later
// empty string is OK, it will default to the public github URL.
if opts.GithubURL != "" && opts.GithubURL != defaultGithubURL {
if !strings.HasSuffix(opts.GithubURL, "/") {
opts.GithubURL += "/"
}
ghURL, err := url.Parse(opts.GithubURL)
if err != nil {
return err
}
tcpPort := "443"
if ghURL.Scheme == "http" {
tcpPort = "80"
}
timeout := time.Duration(1 * time.Second)
_, err = net.DialTimeout("tcp", ghURL.Host+":"+tcpPort, timeout)
if err != nil {
return fmt.Errorf("%s unreachable, error: %s", ghURL.Host, err)
}
}
if opts.SingleSearch != "" {
singleSearchRegex, err = regexp.Compile(opts.SingleSearch)
if err != nil {
return fmt.Errorf("unable to compile regex: %s, %v", opts.SingleSearch, err)
}
}
if opts.Entropy > 8 {
return fmt.Errorf("The maximum level of entropy is 8")
}
if opts.Report != "" {
if !strings.HasSuffix(opts.Report, ".json") && !strings.HasSuffix(opts.Report, ".csv") {
return fmt.Errorf("Report should be a .json or .csv file")
}
dirPath := filepath.Dir(opts.Report)
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
return fmt.Errorf("%s does not exist", dirPath)
}
}
return nil
}
// setLogLevel sets log level for gitleaks. Default is Warning
func (opts *Options) setLogs() {
switch opts.Log {
case "info":
log.SetLevel(log.InfoLevel)
case "debug":
log.SetLevel(log.DebugLevel)
case "warn":
log.SetLevel(log.WarnLevel)
default:
log.SetLevel(log.InfoLevel)
}
log.SetFormatter(&log.TextFormatter{
FullTimestamp: true,
})
}