-
Notifications
You must be signed in to change notification settings - Fork 123
/
conf.go
163 lines (136 loc) · 4.77 KB
/
conf.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
// Copyright 2021-2023 Zenauth Ltd.
// SPDX-License-Identifier: Apache-2.0
package git
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
"go.uber.org/multierr"
"github.com/cerbos/cerbos/internal/config"
"github.com/cerbos/cerbos/internal/storage"
"github.com/cerbos/cerbos/internal/util"
)
const (
confKey = storage.ConfKey + ".git"
defaultOperationTimeout = 60 * time.Second
)
// Conf is required (if driver is set to 'git') configuration for Git storage driver.
// +desc=This section is required only if storage.driver is git.
type Conf struct {
// SSH holds auth details for the SSH protocol.
SSH *SSHAuth `yaml:"ssh,omitempty"`
// HTTPS holds auth details for the HTTPS protocol.
HTTPS *HTTPSAuth `yaml:"https,omitempty"`
// OperationTimeout specifies the timeout for git operations.
OperationTimeout *time.Duration `yaml:"operationTimeout,omitempty" conf:",example=60s"`
// Protocol is the Git protocol to use. Valid values are https, ssh, and file.
Protocol string `yaml:"protocol" conf:"required,example=file"`
// URL is the URL to the Git repo.
URL string `yaml:"url" conf:"required,example=file://${HOME}/tmp/cerbos/policies"`
// Branch is the branch to checkout.
Branch string `yaml:"branch" conf:",example=policies"`
// SubDir is the path under the checked-out Git repo where the policies are stored.
SubDir string `yaml:"subDir,omitempty" conf:",example=policies"`
// CheckoutDir is the local path to checkout the Git repo to.
CheckoutDir string `yaml:"checkoutDir" conf:",example=${HOME}/tmp/cerbos/work"`
// [DEPRECATED] ScratchDir is the directory to use for holding temporary data.
ScratchDir string `yaml:"scratchDir" conf:",ignore"`
// UpdatePollInterval specifies the interval to poll the Git repository for changes. Set to 0 to disable.
UpdatePollInterval time.Duration `yaml:"updatePollInterval" conf:",example=60s"`
}
// SSHAuth holds auth details for the SSH protocol.
type SSHAuth struct {
// The git user. Defaults to git.
User string `yaml:"user" conf:",example=git"`
// The path to the SSH private key file.
PrivateKeyFile string `yaml:"privateKeyFile" conf:",example=${HOME}/.ssh/id_rsa"`
// The password to the SSH private key.
Password string `yaml:"password" conf:",example=pw"`
}
func (sa *SSHAuth) Auth() (transport.AuthMethod, error) {
if sa == nil || sa.PrivateKeyFile == "" {
return nil, nil
}
user := "git"
if sa.User != "" {
user = sa.User
}
return ssh.NewPublicKeysFromFile(user, sa.PrivateKeyFile, sa.Password)
}
// HTTPSAuth holds auth details for the HTTPS protocol.
type HTTPSAuth struct {
// The username to use for authentication.
Username string `yaml:"username" conf:",example=cerbos"`
// The password (or token) to use for authentication.
Password string `yaml:"password" conf:",example=${GITHUB_TOKEN}"`
}
func (ha *HTTPSAuth) Auth() (transport.AuthMethod, error) {
if ha == nil || (ha.Username == "" && ha.Password == "") {
return nil, nil
}
return &http.BasicAuth{Username: ha.Username, Password: ha.Password}, nil
}
func (conf *Conf) Key() string {
return confKey
}
func (conf *Conf) Validate() (errs error) {
switch conf.Protocol {
case "ssh", "http", "https", "file":
default:
errs = multierr.Append(errs, fmt.Errorf("unknown git protocol: %s", conf.Protocol))
}
if conf.URL == "" {
errs = multierr.Append(errs, errors.New("git URL is required"))
}
if conf.CheckoutDir == "" {
cacheDir, err := os.UserCacheDir()
if err != nil {
errs = multierr.Append(errs, fmt.Errorf("checkoutDir unspecified and failed to determine user cache dir: %w", err))
} else {
conf.CheckoutDir = filepath.Join(cacheDir, util.AppName, "git")
}
}
subDir := conf.getSubDir()
if filepath.IsAbs(subDir) || strings.HasPrefix(subDir, "../") || subDir == ".." {
errs = multierr.Append(errs, errors.New("subDir must be a relative path within the repository"))
}
return errs
}
func (conf *Conf) getSubDir() string {
return filepath.ToSlash(filepath.Clean(conf.SubDir))
}
func (conf *Conf) getBranch() string {
branch := "master"
if conf.Branch != "" {
branch = conf.Branch
}
return branch
}
func (conf *Conf) getAuth() (transport.AuthMethod, error) {
switch conf.Protocol {
case "https":
return conf.HTTPS.Auth()
case "ssh":
return conf.SSH.Auth()
default:
return nil, nil
}
}
func (conf *Conf) getOpCtx(parent context.Context) (context.Context, context.CancelFunc) {
if conf.OperationTimeout == nil {
return context.WithTimeout(parent, defaultOperationTimeout)
}
return context.WithTimeout(parent, *conf.OperationTimeout)
}
func GetConf() (*Conf, error) {
conf := &Conf{}
err := config.GetSection(conf)
return conf, err
}