diff --git a/api/core/v3/entity_config.go b/api/core/v3/entity_config.go index 1549dd4313..03e5e6f2b5 100644 --- a/api/core/v3/entity_config.go +++ b/api/core/v3/entity_config.go @@ -5,6 +5,7 @@ import ( "strings" corev2 "github.com/sensu/sensu-go/api/core/v2" + stringutil "github.com/sensu/sensu-go/api/core/v3/internal/strings" ) var entityConfigRBACName = (&corev2.Entity{}).RBACName() @@ -31,3 +32,35 @@ func MergeMapWithPrefix(a map[string]string, b map[string]string, prefix string) a[prefix+k] = v } } + +func redactMap(m map[string]string, redact []string) map[string]string { + if len(redact) == 0 { + redact = corev2.DefaultRedactFields + } + result := make(map[string]string, len(m)) + for k, v := range m { + if stringutil.FoundInArray(k, redact) { + result[k] = corev2.Redacted + } else { + result[k] = v + } + } + return result +} + +// ProduceRedacted redacts the entity according to the entity's Redact fields. +// A redacted copy is returned. The copy contains pointers to the original's +// memory, with different Labels and Annotations. +func (e *EntityConfig) ProduceRedacted() Resource { + if e == nil { + return nil + } + if e.Metadata == nil || (e.Metadata.Labels == nil && e.Metadata.Annotations == nil) { + return e + } + copy := &EntityConfig{} + *copy = *e + copy.Metadata.Annotations = redactMap(e.Metadata.Annotations, e.Redact) + copy.Metadata.Labels = redactMap(e.Metadata.Labels, e.Redact) + return copy +} diff --git a/api/core/v3/entity_config_test.go b/api/core/v3/entity_config_test.go index 568ce1508a..fbc00653ad 100644 --- a/api/core/v3/entity_config_test.go +++ b/api/core/v3/entity_config_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - v2 "github.com/sensu/sensu-go/api/core/v2" + corev2 "github.com/sensu/sensu-go/api/core/v2" ) func TestEntityConfigFields(t *testing.T) { @@ -22,26 +22,26 @@ func TestEntityConfigFields(t *testing.T) { }, { name: "exposes deregister", - args: &EntityConfig{Metadata: &v2.ObjectMeta{}, Deregister: true}, + args: &EntityConfig{Metadata: &corev2.ObjectMeta{}, Deregister: true}, wantKey: "entity_config.deregister", want: "true", }, { name: "exposes class", - args: &EntityConfig{Metadata: &v2.ObjectMeta{}, EntityClass: "agent"}, + args: &EntityConfig{Metadata: &corev2.ObjectMeta{}, EntityClass: "agent"}, wantKey: "entity_config.entity_class", want: "agent", }, { name: "exposes subscriptions", - args: &EntityConfig{Metadata: &v2.ObjectMeta{}, Subscriptions: []string{"www", "unix"}}, + args: &EntityConfig{Metadata: &corev2.ObjectMeta{}, Subscriptions: []string{"www", "unix"}}, wantKey: "entity_config.subscriptions", want: "www,unix", }, { name: "exposes labels", args: &EntityConfig{ - Metadata: &v2.ObjectMeta{ + Metadata: &corev2.ObjectMeta{ Labels: map[string]string{"region": "philadelphia"}, }, }, @@ -58,3 +58,78 @@ func TestEntityConfigFields(t *testing.T) { }) } } + +func TestEntityConfig_ProduceRedacted(t *testing.T) { + tests := []struct { + name string + in *EntityConfig + want *EntityConfig + }{ + { + name: "nil metadata", + in: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Metadata = nil + return cfg + }(), + want: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Metadata = nil + return cfg + }(), + }, + { + name: "nothing to redact", + in: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Metadata.Labels["my_field"] = "test123" + return cfg + }(), + want: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Metadata.Labels["my_field"] = "test123" + return cfg + }(), + }, + { + name: "redact default fields", + in: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Metadata.Labels["my_field"] = "test123" + cfg.Metadata.Labels["password"] = "test123" + return cfg + }(), + want: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Metadata.Labels["my_field"] = "test123" + cfg.Metadata.Labels["password"] = corev2.Redacted + return cfg + }(), + }, + { + name: "redact custom fields", + in: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Redact = []string{"my_field"} + cfg.Metadata.Labels["my_field"] = "test123" + cfg.Metadata.Labels["password"] = "test123" + return cfg + }(), + want: func() *EntityConfig { + cfg := FixtureEntityConfig("test") + cfg.Redact = []string{"my_field"} + cfg.Metadata.Labels["my_field"] = corev2.Redacted + cfg.Metadata.Labels["password"] = "test123" + return cfg + }(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := tt.in + if got := e.ProduceRedacted(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("EntityConfig.ProduceRedacted() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/api/core/v3/internal/strings/strings.go b/api/core/v3/internal/strings/strings.go new file mode 100644 index 0000000000..400bb517eb --- /dev/null +++ b/api/core/v3/internal/strings/strings.go @@ -0,0 +1,60 @@ +package strings + +import ( + "strings" + "unicode" +) + +const ( + lowerAlphaStart = 97 + lowerAlphaStop = 122 +) + +func isAlpha(r rune) bool { + return r >= lowerAlphaStart && r <= lowerAlphaStop +} + +func alphaNumeric(s string) bool { + for _, r := range s { + if !(unicode.IsDigit(r) || isAlpha(r)) { + return false + } + } + return true +} + +func normalize(s string) string { + if alphaNumeric(s) { + return s + } + lowered := strings.ToLower(s) + if alphaNumeric(lowered) { + return lowered + } + trimmed := make([]rune, 0, len(lowered)) + for _, r := range lowered { + if isAlpha(r) { + trimmed = append(trimmed, r) + } + } + return string(trimmed) +} + +// FoundInArray searches array for item without distinguishing between uppercase +// and lowercase and non-alphanumeric characters. Returns true if item is a +// value of array +func FoundInArray(item string, array []string) bool { + if item == "" || len(array) == 0 { + return false + } + + item = normalize(item) + + for i := range array { + if normalize(array[i]) == item { + return true + } + } + + return false +} diff --git a/api/core/v3/internal/strings/strings_test.go b/api/core/v3/internal/strings/strings_test.go new file mode 100644 index 0000000000..d1dfc90c10 --- /dev/null +++ b/api/core/v3/internal/strings/strings_test.go @@ -0,0 +1,34 @@ +package strings + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFoundInArray(t *testing.T) { + var array []string + + found := FoundInArray("Foo", []string{}) + assert.False(t, found) + + array = []string{"foo", "bar"} + found = FoundInArray("Foo", array) + assert.True(t, found) + + array = []string{"foo", "bar"} + found = FoundInArray("FooBar", array) + assert.False(t, found) + + array = []string{"foo", "bar"} + found = FoundInArray("Foo ", array) + assert.True(t, found) + + array = []string{"foo_bar"} + found = FoundInArray("Foo_Bar", array) + assert.True(t, found) + + array = []string{"foobar"} + found = FoundInArray("Foo_Qux", array) + assert.False(t, found) +} diff --git a/api/core/v3/redacter.go b/api/core/v3/redacter.go new file mode 100644 index 0000000000..38d781aedb --- /dev/null +++ b/api/core/v3/redacter.go @@ -0,0 +1,7 @@ +package v3 + +// Redacter can return a redacted copy of the resource +type Redacter interface { + // ProduceRedacted returns a redacted copy of the resource + ProduceRedacted() Resource +} diff --git a/backend/api/generic.go b/backend/api/generic.go index 1803fefe61..625adef719 100644 --- a/backend/api/generic.go +++ b/backend/api/generic.go @@ -169,7 +169,13 @@ func (g *GenericClient) getResource(ctx context.Context, name string, value core if err != nil { return err } - return wrapper.UnwrapInto(value.Resource) + if err := wrapper.UnwrapInto(value.Resource); err != nil { + return err + } + if redacter, ok := value.Resource.(corev3.Redacter); ok { + value.Resource = redacter.ProduceRedacted() + } + return err } return g.Store.GetResource(ctx, name, value) } @@ -209,7 +215,11 @@ func (g *GenericClient) list(ctx context.Context, resources interface{}, pred *s } v2values := make([]corev2.Resource, len(values)) for i := range values { - v2values[i] = corev3.V3ToV2Resource(values[i]) + resource := values[i] + if redacter, ok := resource.(corev3.Redacter); ok { + resource = redacter.ProduceRedacted() + } + v2values[i] = corev3.V3ToV2Resource(resource) } *resourceList = v2values return nil diff --git a/backend/api/generic_test.go b/backend/api/generic_test.go index 963a56f58d..e9117f4bff 100644 --- a/backend/api/generic_test.go +++ b/backend/api/generic_test.go @@ -421,7 +421,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", ResourceName: "default", UserName: "tom", Verb: "get", @@ -430,7 +430,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", UserName: "tom", Verb: "list", }: true, @@ -456,7 +456,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", ResourceName: "default", UserName: "tom", Verb: "get", @@ -465,7 +465,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", ResourceName: "default", UserName: "tom", Verb: "create", @@ -474,7 +474,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", ResourceName: "default", UserName: "tom", Verb: "delete", @@ -483,7 +483,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", ResourceName: "default", UserName: "tom", Verb: "update", @@ -492,7 +492,7 @@ func TestGenericClientStoreV2(t *testing.T) { APIGroup: "core", APIVersion: "v3", Namespace: "default", - Resource: "entity_configs", + Resource: "entities", UserName: "tom", Verb: "list", }: true, @@ -569,6 +569,100 @@ func TestGenericClientStoreV2(t *testing.T) { } } +func TestGenericClientStoreV2_sensu_enterprise_go_GH2484(t *testing.T) { + makeStore := func(entity *corev3.EntityConfig) storev2.Interface { + store := new(storetest.Store) + if entity == nil { + entity = corev3.FixtureEntityConfig("default") + entity.Redact = []string{"password"} + entity.Metadata.Labels["password"] = "test" + entity.Metadata.Labels["my_label"] = "test" + } + wrappedResource, err := storev2.WrapResource(entity) + if err != nil { + panic(err) + } + store.On("Get", mock.Anything).Return(wrappedResource, nil) + store.On("List", mock.Anything, mock.Anything).Return(wrap.List{wrappedResource.(*wrap.Wrapper)}, nil) + return store + } + v3AllAccess := func() authorization.Authorizer { + return &mockAuth{ + attrs: map[authorization.AttributesKey]bool{ + { + APIGroup: "core", + APIVersion: "v3", + Namespace: "default", + Resource: "entities", + ResourceName: "default", + UserName: "tom", + Verb: "get", + }: true, + { + APIGroup: "core", + APIVersion: "v3", + Namespace: "default", + Resource: "entities", + ResourceName: "default", + UserName: "tom", + Verb: "create", + }: true, + { + APIGroup: "core", + APIVersion: "v3", + Namespace: "default", + Resource: "entities", + ResourceName: "default", + UserName: "tom", + Verb: "delete", + }: true, + { + APIGroup: "core", + APIVersion: "v3", + Namespace: "default", + Resource: "entities", + ResourceName: "default", + UserName: "tom", + Verb: "update", + }: true, + { + APIGroup: "core", + APIVersion: "v3", + Namespace: "default", + Resource: "entities", + UserName: "tom", + Verb: "list", + }: true, + }, + } + } + + ctx := contextWithUser(defaultContext(), "tom", nil) + client := defaultV2TestClient(makeStore(nil), v3AllAccess()) + listVal := []corev2.Resource{} + if err := client.List(ctx, &listVal, &store.SelectionPredicate{}); err != nil { + t.Fatal(err) + } + if listVal[0].GetObjectMeta().Labels["password"] != corev2.Redacted { + t.Errorf("Labels['password'] = %s, got: %s", corev2.Redacted, listVal[0].GetObjectMeta().Labels["password"]) + } + if listVal[0].GetObjectMeta().Labels["my_label"] != "test" { + t.Errorf("Labels['my_label'] = %s, got: %s", "test", listVal[0].GetObjectMeta().Labels["my_label"]) + } + + client = defaultV2TestClient(makeStore(nil), v3AllAccess()) + getVal := corev3.V2ResourceProxy{Resource: &corev3.EntityConfig{}} + if err := client.Get(ctx, "default", &getVal); err != nil { + t.Fatal(err) + } + if getVal.GetObjectMeta().Labels["password"] != corev2.Redacted { + t.Errorf("Labels['password'] = %s, got: %s", corev2.Redacted, getVal.GetObjectMeta().Labels["password"]) + } + if getVal.GetObjectMeta().Labels["my_label"] != "test" { + t.Errorf("Labels['my_label'] = %s, got: %s", "test", getVal.GetObjectMeta().Labels["my_label"]) + } +} + func TestSetTypeMetaV3Resource(t *testing.T) { client := &GenericClient{} err := client.SetTypeMeta(corev2.TypeMeta{ diff --git a/go.mod b/go.mod index 25456d603b..5a1d1b5d73 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/sensu/lasr v1.2.1 github.com/sensu/sensu-go/api/core/v2 v2.14.0 - github.com/sensu/sensu-go/api/core/v3 v3.6.2 + github.com/sensu/sensu-go/api/core/v3 v3.6.3-0.20220912182551-a5a7db519e68 github.com/sensu/sensu-go/types v0.10.0 github.com/shirou/gopsutil/v3 v3.21.12 github.com/sirupsen/logrus v1.7.0 diff --git a/go.sum b/go.sum index 2269ce740a..f525d49320 100644 --- a/go.sum +++ b/go.sum @@ -55,7 +55,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= @@ -65,7 +64,6 @@ github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoC github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -100,7 +98,6 @@ github.com/emicklei/proto v1.1.0 h1:3OWZhkr68eGPyCY1AtNh1u+5IyBiVVDJMXKRX9cOFgY= github.com/emicklei/proto v1.1.0/go.mod h1:Dqn751twH9SasYqvA59Lb9Hz+itoJgmMoivX6k7OPZc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= @@ -181,7 +178,6 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -390,7 +386,6 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/schollz/progressbar/v2 v2.13.2/go.mod h1:6YZjqdthH6SCZKv2rqGryrxPtfmRB/DWZxSMfCXPyD8= @@ -402,6 +397,10 @@ github.com/sensu/sensu-go/api/core/v2 v2.14.0/go.mod h1:XCgUjY78ApTahizBz/pkc5KU github.com/sensu/sensu-go/api/core/v3 v3.6.1/go.mod h1:aqNOkJxkrwRq+rPW47XtVWeb5Rk1K5adlCZGBW9nsvM= github.com/sensu/sensu-go/api/core/v3 v3.6.2 h1:NEkHcPxkaYwPlH4gG6kgvdvYLlwBBaswMHscA7X3V+4= github.com/sensu/sensu-go/api/core/v3 v3.6.2/go.mod h1:aqNOkJxkrwRq+rPW47XtVWeb5Rk1K5adlCZGBW9nsvM= +github.com/sensu/sensu-go/api/core/v3 v3.6.3-0.20220912171820-366b64ed1a62 h1:PeP63bXXwwB586EjCb73jg0oqzE3Tg3aOH38g9qG58k= +github.com/sensu/sensu-go/api/core/v3 v3.6.3-0.20220912171820-366b64ed1a62/go.mod h1:n2dhnBTovMrzmE1P0D7gvEbUG7TPH6hdtr7qvoPf/sY= +github.com/sensu/sensu-go/api/core/v3 v3.6.3-0.20220912182551-a5a7db519e68 h1:t5AsMszceHgj4yGHflRi705L3mZbb15yi5pRJfiWmy8= +github.com/sensu/sensu-go/api/core/v3 v3.6.3-0.20220912182551-a5a7db519e68/go.mod h1:n2dhnBTovMrzmE1P0D7gvEbUG7TPH6hdtr7qvoPf/sY= github.com/sensu/sensu-go/types v0.10.0 h1:sm+dLuqEEECVxjW5EfXkU5weGPwrg/Jymbm28HdQpl8= github.com/sensu/sensu-go/types v0.10.0/go.mod h1:vFZJ9TYBAjSPYtYt+82PpS9P6m73Vzr4O23lmJonzrA= github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA= @@ -455,7 +454,6 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/willf/pad v0.0.0-20160331131008-b3d780601022 h1:W5wMm7sF44Z3K9bpq+CHOMOipvLHN1ElD6nyQbbiy/0= @@ -470,7 +468,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -537,8 +534,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -586,7 +581,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -634,7 +628,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -651,12 +644,9 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=