Skip to content

Commit 789deb1

Browse files
chrysom bump, validation config fix (#91)
* updated errors to have more information * change validation config field name to match * bumped argus version * add mapstructure tag for proper yaml unmarshaling * updated changelog * added chrysom version * fixed error string * prep for release
1 parent 3542233 commit 789deb1

8 files changed

+199
-56
lines changed

CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## [Unreleased]
88

9+
## [v0.3.4]
10+
- Added more details to some validation errors. [#91](https://github.com/xmidt-org/ancla/pull/91)
11+
- Fixed naming mismatch for Validator config: changed name in Config struct to what we send in yaml. [#91](https://github.com/xmidt-org/ancla/pull/91)
12+
- Bumped chrysom to v0.6.0: updated code to create basic and listener clients. [#91](https://github.com/xmidt-org/ancla/pull/91)
13+
914
## [v0.3.3]
1015
- Removed legacy logic condition for inserting a webhook. [#85](https://github.com/xmidt-org/ancla/pull/85)
1116
- Changed webhook address handling. [#84](https://github.com/xmidt-org/ancla/pull/84)
@@ -78,7 +83,8 @@ internalWebhooks. [#80](https://github.com/xmidt-org/ancla/pull/80)
7883
## [v0.1.0]
7984
- Initial release
8085

81-
[Unreleased]: https://github.com/xmidt-org/ancla/compare/v0.3.3...HEAD
86+
[Unreleased]: https://github.com/xmidt-org/ancla/compare/v0.3.4...HEAD
87+
[v0.3.4]: https://github.com/xmidt-org/ancla/compare/0.3.3...v0.3.4
8288
[v0.3.3]: https://github.com/xmidt-org/ancla/compare/0.3.2...v0.3.3
8389
[v0.3.2]: https://github.com/xmidt-org/ancla/compare/0.3.1...v0.3.2
8490
[v0.3.1]: https://github.com/xmidt-org/ancla/compare/0.3.0...v0.3.1

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ go 1.15
55
require (
66
github.com/go-kit/kit v0.10.0
77
github.com/golang-jwt/jwt v3.2.1+incompatible
8-
github.com/spf13/cast v1.3.1
8+
github.com/spf13/cast v1.4.1
99
github.com/stretchr/testify v1.7.0
10-
github.com/xmidt-org/argus v0.5.1
10+
github.com/xmidt-org/argus v0.6.0
1111
github.com/xmidt-org/bascule v0.10.2
1212
github.com/xmidt-org/httpaux v0.2.1
1313
github.com/xmidt-org/webpa-common/v2 v2.0.1

go.sum

+135-27
Large diffs are not rendered by default.

service.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type Service interface {
5959
// Config contains information needed to initialize the webhook service.
6060
type Config struct {
6161
// Argus contains configuration to initialize an Argus client.
62-
Argus chrysom.ClientConfig
62+
Argus ArgusConfig
6363

6464
// Logger for this package.
6565
// Gets passed to Argus config before initializing the client.
@@ -81,12 +81,17 @@ type Config struct {
8181
// checking the validity of the partnerIDs in the request
8282
DisablePartnerIDs bool
8383

84-
// WebhookValidationConfig provides options for validating the webhook's URL and TTL
84+
// Validation provides options for validating the webhook's URL and TTL
8585
// related fields. Some validation happens regardless of the configuration:
8686
// URLs must be a valid URL structure, the Matcher.DeviceID values must
8787
// compile into regular expressions, and the Events field must have at
8888
// least one value and all values must compile into regular expressions.
89-
WebhookValidationConfig ValidatorConfig
89+
Validation ValidatorConfig
90+
}
91+
92+
type ArgusConfig struct {
93+
chrysom.BasicClientConfig `mapstructure:",squash"`
94+
Listen chrysom.ListenerClientConfig
9095
}
9196

9297
type service struct {
@@ -193,21 +198,25 @@ func Initialize(cfg Config, getLogger func(ctx context.Context) log.Logger, setL
193198
m := &chrysom.Measures{
194199
Polls: cfg.MetricsProvider.NewCounterVec(chrysom.PollCounter),
195200
}
196-
argus, err := chrysom.NewClient(cfg.Argus, m, getLogger, setLogger)
201+
basic, err := chrysom.NewBasicClient(cfg.Argus.BasicClientConfig, getLogger, setLogger)
202+
if err != nil {
203+
return nil, nil, fmt.Errorf("failed to create chrysom basic client: %v", err)
204+
}
205+
listener, err := chrysom.NewListenerClient(cfg.Argus.Listen, setLogger, m, basic)
197206
if err != nil {
198-
return nil, nil, err
207+
return nil, nil, fmt.Errorf("failed to create chrysom listener client: %v", err)
199208
}
200209

201210
svc := &service{
202211
logger: cfg.Logger,
203-
argus: argus,
212+
argus: basic,
204213
config: cfg,
205214
now: time.Now,
206215
}
207216

208-
argus.Start(context.Background())
217+
listener.Start(context.Background())
209218

210-
return svc, func() { argus.Stop(context.Background()) }, nil
219+
return svc, func() { listener.Stop(context.Background()) }, nil
211220
}
212221

213222
func prepArgusConfig(cfg *Config, watches ...Watch) error {

service_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func TestAdd(t *testing.T) {
9696
{
9797
Description: "Unknown push result",
9898
PushItemResults: pushItemResults{
99-
result: "unknownResult",
99+
result: chrysom.UnknownPushResult,
100100
},
101101
ExpectedErr: errNonSuccessPushResult,
102102
},

webhookURLValidator.go

+23-13
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ var (
3030
errInvalidFailureURL = errors.New("invalid Failure URL")
3131
errInvalidAlternativeURL = errors.New("invalid Alternative URL(s)")
3232
errURLIsNotHTTPS = errors.New("URL scheme is not HTTPS")
33-
errInvalidHost = errors.New("invalid host")
33+
errInvalidHost = errors.New("host is blocked")
3434
errIPGivenAsHost = errors.New("cannot use IP as host")
3535
errLoopbackGivenAsHost = errors.New("cannot use loopback host")
3636
errIPinInvalidSubnets = errors.New("IP is within a blocked subnet")
3737
errInvalidSubnet = errors.New("invalid subnet")
3838
errNoSuchHost = errors.New("host does not exist")
3939
errBadURLProtocol = errors.New("bad URL protocol")
40+
errEmptyURL = errors.New("url cannot be an empty string")
4041
)
4142

4243
// filterNil takes out all entries of Nil value from the slice.
@@ -55,6 +56,10 @@ func filterNil(vs []ValidURLFunc) (filtered []ValidURLFunc) {
5556
func GoodConfigURL(vs []ValidURLFunc) ValidatorFunc {
5657
vs = filterNil(vs)
5758
return func(w Webhook) error {
59+
if w.Config.URL == "" {
60+
return fmt.Errorf("%w: %v",
61+
errInvalidURL, errEmptyURL)
62+
}
5863
parsedURL, err := url.ParseRequestURI(w.Config.URL)
5964
if err != nil {
6065
return fmt.Errorf("%w: %v", errInvalidURL, err)
@@ -99,16 +104,19 @@ func GoodAlternativeURLs(vs []ValidURLFunc) ValidatorFunc {
99104
return func(w Webhook) error {
100105
for _, u := range w.Config.AlternativeURLs {
101106
if u == "" {
102-
return errInvalidAlternativeURL
107+
return fmt.Errorf("%w: %v",
108+
errInvalidAlternativeURL, errEmptyURL)
103109
}
104110
parsedAlternativeURL, err := url.ParseRequestURI(u)
105111
if err != nil {
106-
return fmt.Errorf("%w: %v", errInvalidAlternativeURL, err)
112+
return fmt.Errorf("%w '%s': %v",
113+
errInvalidAlternativeURL, u, err)
107114
}
108115
for _, f := range vs {
109116
err = f(parsedAlternativeURL)
110117
if err != nil {
111-
return fmt.Errorf("%w: %v", errInvalidAlternativeURL, err)
118+
return fmt.Errorf("%w '%s': %v",
119+
errInvalidAlternativeURL, u, err)
112120
}
113121
}
114122
}
@@ -122,10 +130,10 @@ func GoodAlternativeURLs(vs []ValidURLFunc) ValidatorFunc {
122130
func GoodURLScheme(httpsOnly bool) ValidURLFunc {
123131
return func(u *url.URL) error {
124132
if u.Scheme != "https" && u.Scheme != "http" {
125-
return errBadURLProtocol
133+
return fmt.Errorf("%w: %s", errBadURLProtocol, u.Scheme)
126134
}
127135
if httpsOnly && u.Scheme != "https" {
128-
return errURLIsNotHTTPS
136+
return fmt.Errorf("%w: %s", errURLIsNotHTTPS, u.Scheme)
129137
}
130138
return nil
131139
}
@@ -144,7 +152,7 @@ func RejectHosts(invalidHosts []string) ValidURLFunc {
144152
return func(u *url.URL) error {
145153
for _, v := range ih {
146154
if strings.Contains(u.Host, v) {
147-
return errInvalidHost
155+
return fmt.Errorf("%w: %s", errInvalidHost, u.Host)
148156
}
149157
}
150158
return nil
@@ -158,7 +166,7 @@ func RejectAllIPs() ValidURLFunc {
158166
host := u.Hostname()
159167
ip := net.ParseIP(host)
160168
if ip != nil {
161-
return errIPGivenAsHost
169+
return fmt.Errorf("%w: %v", errIPGivenAsHost, host)
162170
}
163171
return nil
164172
}
@@ -171,15 +179,16 @@ func RejectLoopback() ValidURLFunc {
171179
host := u.Hostname()
172180
ip := net.ParseIP(host)
173181
if ip != nil && ip.IsLoopback() {
174-
return errLoopbackGivenAsHost
182+
return fmt.Errorf("%w: %v", errLoopbackGivenAsHost, ip)
175183
}
176184
ips, err := net.LookupIP(host)
177185
if err != nil {
178186
return fmt.Errorf("%w: %v", errNoSuchHost, err)
179187
}
180188
for _, i := range ips {
181189
if i.IsLoopback() {
182-
return errLoopbackGivenAsHost
190+
return fmt.Errorf("%w: %v lookup includes %v",
191+
errLoopbackGivenAsHost, host, i)
183192
}
184193
}
185194
return nil
@@ -193,19 +202,20 @@ func InvalidSubnets(i []string) (ValidURLFunc, error) {
193202
for _, sp := range i {
194203
_, n, err := net.ParseCIDR(sp)
195204
if err != nil {
196-
return nil, errInvalidSubnet
205+
return nil, fmt.Errorf("%w %s: %v", errInvalidSubnet, sp, err)
197206
}
198207
invalidSubnets = append(invalidSubnets, n)
199208
}
200209
return func(u *url.URL) error {
201210
ips, err := net.LookupIP(u.Hostname())
202211
if err != nil {
203-
return errInvalidURL
212+
return fmt.Errorf("%w: %v", errInvalidURL, err)
204213
}
205214
for _, d := range ips {
206215
for _, s := range invalidSubnets {
207216
if s.Contains(d) {
208-
return errIPinInvalidSubnets
217+
return fmt.Errorf("%w: ip %s in %s",
218+
errIPinInvalidSubnets, d, s)
209219
}
210220
}
211221
}

webhookURLValidator_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ func TestGoodConfigURL(t *testing.T) {
9191
expectedErr: errInvalidURL,
9292
validURLFuncs: simpleFuncs,
9393
},
94+
{
95+
desc: "Parse Failure",
96+
webhook: Webhook{Config: DeliveryConfig{URL: "\\\\"},
97+
FailureURL: ""},
98+
expectedErr: errInvalidURL,
99+
validURLFuncs: simpleFuncs,
100+
},
94101
{
95102
desc: "No https url Failure",
96103
webhook: Webhook{Config: DeliveryConfig{URL: "http://www.google.com/"},

webhookValidator.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package ancla
1919

2020
import (
2121
"errors"
22+
"fmt"
2223
"net/url"
2324
"regexp"
2425
"time"
@@ -31,8 +32,8 @@ var (
3132
errInvalidDuration = errors.New("duration value of webhook is out of bounds")
3233
errInvalidUntil = errors.New("until value of webhook is out of bounds")
3334
errUntilDurationAbsent = errors.New("until and duration are both absent")
34-
errInvalidTTL = errors.New("invalid TTL")
35-
errInvalidJitter = errors.New("invalid jitter")
35+
errInvalidTTL = errors.New("TTL must be non-negative")
36+
errInvalidJitter = errors.New("jitter must be non-negative")
3637
)
3738

3839
// Validator is a WebhookValidator that allows access to the Validate function.
@@ -108,7 +109,8 @@ func CheckDuration(maxTTL time.Duration) (ValidatorFunc, error) {
108109
}
109110
return func(w Webhook) error {
110111
if maxTTL < w.Duration || w.Duration < 0 {
111-
return errInvalidDuration
112+
return fmt.Errorf("%w: %v not between 0 and %v",
113+
errInvalidDuration, w.Duration, maxTTL)
112114
}
113115
return nil
114116
}, nil
@@ -131,7 +133,8 @@ func CheckUntil(jitter time.Duration, maxTTL time.Duration, now func() time.Time
131133
limit := (now().Add(maxTTL)).Add(jitter)
132134
proposed := (w.Until)
133135
if proposed.After(limit) {
134-
return errInvalidUntil
136+
return fmt.Errorf("%w: %v after %v",
137+
errInvalidUntil, proposed.String(), limit.String())
135138
}
136139
return nil
137140
}, nil

0 commit comments

Comments
 (0)