From 6710bd1f08faccbd4768ec77223518990a48c1f1 Mon Sep 17 00:00:00 2001 From: Zoran Regvart Date: Tue, 3 Dec 2024 16:15:13 +0100 Subject: [PATCH] Simple macro benchmark Implementation of a simple macro benchmark executing `ec validate image` with the fixed state and no external dependencies. For this the OCI distribution registry is run in a container with the data from the `benchmark/simple/data.tar.gz` that contains the copy of all images/blobs that the command and the policy rules currently access and the git repository. The benchmark outputs in the golang standard benchmark format that can be utilized with tools in the golang benchmarking ecosystem. Due to the global `downloadCache` variable in `internal/policy/source/source.go` the benchmark cannot be run in parallel. So only invoking the benchmark once is currently possible. Reference: https://issues.redhat.com/browse/EC-968 --- .gitleaks.toml | 7 + Makefile | 7 + benchmark/README.md | 12 ++ benchmark/internal/registry/fake_quay.cer | 20 +++ benchmark/internal/registry/fake_quay.key | 28 ++++ benchmark/internal/registry/registry.go | 167 ++++++++++++++++++++++ benchmark/internal/suite/closer.go | 19 +++ benchmark/internal/suite/suite.go | 32 +++++ benchmark/internal/untar/untar.go | 91 ++++++++++++ benchmark/offliner/README.md | 8 ++ benchmark/offliner/base_images.go | 133 +++++++++++++++++ benchmark/offliner/nab.go | 25 ++++ benchmark/offliner/offliner.go | 139 ++++++++++++++++++ benchmark/offliner/offliner_test.go | 49 +++++++ benchmark/offliner/referrers.go | 63 ++++++++ benchmark/offliner/refs.go | 44 ++++++ benchmark/offliner/related.go | 91 ++++++++++++ benchmark/offliner/scans.go | 117 +++++++++++++++ benchmark/offliner/subjects.go | 90 ++++++++++++ benchmark/simple/.gitattributes | 1 + benchmark/simple/data.tar.gz | 3 + benchmark/simple/prepare_data.sh | 46 ++++++ benchmark/simple/simple.go | 123 ++++++++++++++++ cmd/root.go | 23 +-- go.mod | 32 ++++- go.sum | 77 ++++++++-- 26 files changed, 1426 insertions(+), 21 deletions(-) create mode 100644 .gitleaks.toml create mode 100644 benchmark/README.md create mode 100644 benchmark/internal/registry/fake_quay.cer create mode 100644 benchmark/internal/registry/fake_quay.key create mode 100644 benchmark/internal/registry/registry.go create mode 100644 benchmark/internal/suite/closer.go create mode 100644 benchmark/internal/suite/suite.go create mode 100644 benchmark/internal/untar/untar.go create mode 100644 benchmark/offliner/README.md create mode 100644 benchmark/offliner/base_images.go create mode 100644 benchmark/offliner/nab.go create mode 100644 benchmark/offliner/offliner.go create mode 100644 benchmark/offliner/offliner_test.go create mode 100644 benchmark/offliner/referrers.go create mode 100644 benchmark/offliner/refs.go create mode 100644 benchmark/offliner/related.go create mode 100644 benchmark/offliner/scans.go create mode 100644 benchmark/offliner/subjects.go create mode 100644 benchmark/simple/.gitattributes create mode 100644 benchmark/simple/data.tar.gz create mode 100755 benchmark/simple/prepare_data.sh create mode 100644 benchmark/simple/simple.go diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000..9fb39beb3 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,7 @@ +[allowlist] + description = "Project allowlist" + + paths = [ + '''benchmark\/internal\/registry\/fake_quay.key$''', + '''benchmark\/simple\/data.tar.gz$''', + ] diff --git a/Makefile b/Makefile index 0f4122def..cfc85f52a 100644 --- a/Makefile +++ b/Makefile @@ -144,6 +144,13 @@ feature_%: ## Run acceptance tests for a single feature file, e.g. make feature_ scenario_%: build ## Run acceptance tests for a single scenario, e.g. make scenario_inline_policy @cd acceptance && go test -test.run 'TestFeatures/$*' +benchmark_%: + @cd benchmark/$* + @go run . + +.PHONY: benchmark +benchmark: benchmark_simple ## Run benchmarks + .PHONY: ci ci: test lint-fix acceptance ## Run the usual required CI tasks diff --git a/benchmark/README.md b/benchmark/README.md new file mode 100644 index 000000000..db98e7874 --- /dev/null +++ b/benchmark/README.md @@ -0,0 +1,12 @@ +# Benchmarks of ec CLI + +Benchmarks within this directory use the [golang +benchmarking](golang.org/x/benchmarks/) package and output in the [standard +benchmark +format](https://go.googlesource.com/proposal/+/master/design/14313-benchmark-format.md). + +Each benchmark is built as a standalone executable with no external dependency +other than any data that is contained within it. Benchmarks are run from within +the directory they're defined in, simply by running `go run .`, additional +arguments can be passed in, for example `-benchnum 10` to run the benchmark 10 +times. diff --git a/benchmark/internal/registry/fake_quay.cer b/benchmark/internal/registry/fake_quay.cer new file mode 100644 index 000000000..31b65f6cf --- /dev/null +++ b/benchmark/internal/registry/fake_quay.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOjCCAiKgAwIBAgIUOc/vG5o8pNnIBCIYsrYJ01jkmfEwDQYJKoZIhvcNAQEL +BQAwFzEVMBMGA1UEAwwMYmVuY2htYXJrLmVjMB4XDTI0MTIwOTE1MzIyMVoXDTM0 +MTIwNzE1MzIyMVowFzEVMBMGA1UEAwwMYmVuY2htYXJrLmVjMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnVIvUGHA2XFScaRcN8vxNiuDShN4SNuCWcdC +cbzvCbA7yu4v2LJBqsbDIs5zWcr9kb15vg0Cg3dCHztnsJCmFIwp6lKc3l60eD4+ +Qke2YnD3cUB/P4A7jMUC2kEjjlqdnoLw6IIwt7D6JZeaZhDpPfGyf3llxoVdT5+J +dfBtn6U4WnYqqTg7vccoe0RTXkotLAUMyshd00QaGKIOZ5HdzDBXHUVszTU+Vidf +9xyxndDVlxnE70zWv/jeZLhgnkxMRzoi0q2hq25TeugQ+yrGKVD4UBB6CaGWgAIN +Sw0iTFmYd+0uBVpTYF8KLO2jc/bNqFGJn2t/+P88XqfHTCZVfwIDAQABo34wfDA5 +BgNVHREEMjAwggdxdWF5LmlvghpyZWdpc3RyeS5hY2Nlc3MucmVkaGF0LmNvbYIJ +bG9jYWxob3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNV +HQ4EFgQUP3lNVxeEEpMjoKQ2wPk6hhLsXOwwDQYJKoZIhvcNAQELBQADggEBAFKp +MpYwkR5vb73JsRATYr6H/A5bRAjVg+NoMklOJ5lu5PtwomD0rlD8OIJeXuT57Bsy +PAukG7gXlHk0zJ3cExxsys+jscsGKi2+gKEWvOYj06Z5xug7GPZyoA9r6MOKclZJ +VXCxpQfkl5pGDQiIhtpvuADt8oBogx4mwDhP16WBz/5BkKIpsLn7jGZOUYaSrjG3 +OLf5AArhHzs0rRRcaCjbybuah8nQMMqG7Q6bz7jF4szCeIL7ndWro2U5kgVVMrXS +5zbEklvW5OXFO/UREiY+5YBAu6gCr0APFLAQi5qfAhKpbQkjZ28unuB/3aQlT0kR +wHo3oDNZDNaIwBoP/54= +-----END CERTIFICATE----- diff --git a/benchmark/internal/registry/fake_quay.key b/benchmark/internal/registry/fake_quay.key new file mode 100644 index 000000000..f72c8e78e --- /dev/null +++ b/benchmark/internal/registry/fake_quay.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdUi9QYcDZcVJx +pFw3y/E2K4NKE3hI24JZx0JxvO8JsDvK7i/YskGqxsMiznNZyv2RvXm+DQKDd0If +O2ewkKYUjCnqUpzeXrR4Pj5CR7ZicPdxQH8/gDuMxQLaQSOOWp2egvDogjC3sPol +l5pmEOk98bJ/eWXGhV1Pn4l18G2fpThadiqpODu9xyh7RFNeSi0sBQzKyF3TRBoY +og5nkd3MMFcdRWzNNT5WJ1/3HLGd0NWXGcTvTNa/+N5kuGCeTExHOiLSraGrblN6 +6BD7KsYpUPhQEHoJoZaAAg1LDSJMWZh37S4FWlNgXwos7aNz9s2oUYmfa3/4/zxe +p8dMJlV/AgMBAAECggEASM1Xh+M002tVs7FT255NKbxJLWaFK3IpiFJltSyxkdI0 +WVyQV79mFBmXA+x2BP+jCGaeiAyNNTljKADdox/NO4UBgKZqYZ2B9oMXXKTDChss +5wPp3wEAjcw93bJ3OdFFT61YvsBAu0DzAaJ+mO0Kgtfuun77Ujs1SzuQ6Tsx/8ZD +STr8q7DcMAd6afHFFk5NZDqyFPgzmEMUWRFy7BH/vLLEgdRi7I7UbTYhjpP7uyjF +/0HLSjBQJr58554CyL11OcVOwqktKZYKMVsCNWg6l4uhYxg0ChyJgO+PuUhPqh1i +eIybcaDUVQ0LG/gBYzDlnw8yNXPO4+HX+MdIXafBAQKBgQDZx6m2rsI3L4M0ow89 +T6L8jMrFF6bUp2PBVPOYvobk4de3x7ma4WwK212l869A2u536+8BlBaiZN0yRSmI +XXX0oL8JfqTO7d5efa9zHdkEN+t7iwVFWsYe74jjVR/oOyW7ZJ07gP/kZudbm8uk +DnGzEGsjTYo7K6dEcEiXXmZiDwKBgQC47j8iR7v6a0E7EzEcM6FIpAV8tlpj0wUt +pXKHPRdMQaOi39YyNWCGGake7bRCGz2ni1zqSVqVIcm6yvzlS/o3lLMTUYlUxtqt +0cGrTJXkyhwkyoAJg0vwU43BJkbUNsX0y5revv/T4TaVTYK4dv2RTv8Jbdp6sT7i +B6I7tFmFkQKBgQDQShe24rRchbPOrzoPINC5DYuOMA3fC+3r5e1KJMftt1dTrdGG +IZ3tUFvkMgpnVD2KMvyYHOP9E80/nEiZ5RHBE9FDKn5Eb9sjssAQsPZ0A2vU8GTt +LWGaCu14yFzJB3ESJqv/UmTsNcOHqZ1+XlY+tjBSRoI0D49edKnpJF913wKBgQCn +WSHUuamIIYr0FJf6d1ZaT+OPSc1eTFWBSxjq/QOaREP6XiiNYvQoJgx/KohW0iPm +/Bxm/15zWhIdcReNwEV8CppKvxxRlWnKpehmRXXXhnYVbRKUiTYtEs9SnHq4C6Dz +t1Q8ggcsC7/DOFM07qjj1+K++6QcJ01KabIL6VahoQKBgGNCgw4+0291OA8nwjXl +HNu9WBzJVHsAL9RDvrL6c4wcUWmhJTUcKN/TnndYN5SdvrOzZ2RjysS8KZoLnHgI +c41uBNLvGtE9RPuzFe7U3zt9t80d4gcjy92tBru6xszPIgmKsUe8Hrl2EWbJvCET +/BbfoyzzqH3f+vYm25GFSIy5 +-----END PRIVATE KEY----- diff --git a/benchmark/internal/registry/registry.go b/benchmark/internal/registry/registry.go new file mode 100644 index 000000000..30b715887 --- /dev/null +++ b/benchmark/internal/registry/registry.go @@ -0,0 +1,167 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//type Closer func() +// SPDX-License-Identifier: Apache-2.0 + +package registry + +import ( + "context" + "crypto/tls" + "crypto/x509" + _ "embed" + "fmt" + "log" + "net" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/enterprise-contract/ec-cli/benchmark/internal/suite" + "github.com/smarty/cproxy/v2" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/modules/registry" + "github.com/testcontainers/testcontainers-go/wait" +) + +//go:embed fake_quay.cer +var certificate []byte + +//go:embed fake_quay.key +var key []byte + +type registryCloser struct { + tempDir string + container *registry.RegistryContainer + proxy *httptest.Server +} + +func (r *registryCloser) Close() { + if r == nil { + return + } + + if r.tempDir != "" { + _ = os.RemoveAll(r.tempDir) + } + + if r.container != nil { + _ = r.container.Terminate(context.Background()) + } + + if r.proxy != nil { + r.proxy.Close() + } +} + +type registryProxy struct { + registry string +} + +func (f *registryProxy) IsAuthorized(_ http.ResponseWriter, req *http.Request) bool { + req.RequestURI = fmt.Sprintf("https://%s/", f.registry) + req.URL, _ = url.Parse(req.RequestURI) + req.Host = f.registry + + return true +} + +func Launch(data string) (suite.Closer, error) { + ctx := context.Background() + + env := testcontainers.WithEnv(map[string]string{ + "REGISTRY_HTTP_TLS_CERTIFICATE": "/tls/fake_quay.cer", + "REGISTRY_HTTP_TLS_KEY": "/tls/fake_quay.key", + }) + + dir, err := os.MkdirTemp("", "ec-benchmark-tls-*") + if err != nil { + return nil, err + } + closer := ®istryCloser{dir, nil, nil} + + if err := os.Setenv("https_proxy", "http://localhost:3128"); err != nil { + return nil, err + } + + if err := os.Chmod(dir, 0755); err != nil { + return closer.Close, err + } + + certPath := path.Join(dir, "fake_quay.cer") + if err := os.WriteFile(certPath, certificate, 0644); err != nil { + return closer.Close, err + } + + if err := os.Setenv("SSL_CERT_FILE", certPath); err != nil { + return closer.Close, err + } + + if err := os.WriteFile(path.Join(dir, "fake_quay.key"), key, 0644); err != nil { + return closer.Close, err + } + + rp := registryProxy{} + proxy := cproxy.New(cproxy.Options.Filter(&rp), cproxy.Options.Logger(log.Default())) + proxyServer := httptest.NewUnstartedServer(proxy) + proxyServer.Listener, err = net.Listen("tcp", "127.0.0.1:3128") + if err != nil { + return closer.Close, err + } + proxyServer.Config.ErrorLog = log.Default() + proxyServer.Start() + closer.proxy = proxyServer + + tlsMount := testcontainers.WithHostConfigModifier(func(hostConfig *container.HostConfig) { + hostConfig.Binds = append(hostConfig.Binds, fmt.Sprintf("%s:/tls:ro,Z", dir)) + }) + + roots := x509.NewCertPool() + roots.AppendCertsFromPEM(certificate) + waitStrategy := testcontainers.WithWaitStrategy(wait.ForHTTP("/"). + WithPort("5000/tcp"). + WithTLS(true, &tls.Config{ + RootCAs: roots, + }). + WithStartupTimeout(10 * time.Second)) + + opts := []testcontainers.ContainerCustomizer{ + registry.WithData(data), + env, + tlsMount, + waitStrategy, + } + + if false { + opts = append(opts, + testcontainers.WithConfigModifier(func(config *container.Config) { + config.AttachStdout = true + }), + testcontainers.WithLogger(log.Default())) + } + + r, err := registry.Run(ctx, "registry:2.8.3", opts...) + if err != nil { + return closer.Close, err + } + closer.container = r + + rp.registry = r.RegistryName + + return closer.Close, nil +} diff --git a/benchmark/internal/suite/closer.go b/benchmark/internal/suite/closer.go new file mode 100644 index 000000000..15101c10f --- /dev/null +++ b/benchmark/internal/suite/closer.go @@ -0,0 +1,19 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package suite + +type Closer func() diff --git a/benchmark/internal/suite/suite.go b/benchmark/internal/suite/suite.go new file mode 100644 index 000000000..789e2fb13 --- /dev/null +++ b/benchmark/internal/suite/suite.go @@ -0,0 +1,32 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package suite + +import ( + "io" + + "github.com/enterprise-contract/ec-cli/cmd" + "github.com/enterprise-contract/ec-cli/cmd/root" +) + +func Execute(args []string) error { + c := root.NewRootCmd() + cmd.AddCommandsTo(c) + c.SetArgs(args) + c.SetOutput(io.Discard) + return c.Execute() +} diff --git a/benchmark/internal/untar/untar.go b/benchmark/internal/untar/untar.go new file mode 100644 index 000000000..5f875b50a --- /dev/null +++ b/benchmark/internal/untar/untar.go @@ -0,0 +1,91 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package untar + +import ( + "compress/gzip" + "errors" + "fmt" + "io" + "io/fs" + "math" + "os" + "path" + + "github.com/google/safearchive/tar" +) + +func UnTar(a string) (string, error) { + dir, err := os.MkdirTemp("", "ec-benchmark") + if err != nil { + return "", err + } + + archive, err := os.Open(a) + if err != nil { + return "", err + } + defer archive.Close() + + gz, err := gzip.NewReader(archive) + if err != nil { + return "", err + } + defer gz.Close() + + t := tar.NewReader(gz) + for { + hdr, err := t.Next() + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return "", err + } + + dst := path.Join(dir, path.Clean(hdr.Name)) + if hdr.Mode < 0 || hdr.Mode > math.MaxUint32 { + panic(fmt.Sprintf("weird tar header mode: %d", hdr.Mode)) + } + mode := fs.FileMode(hdr.Mode) + + switch hdr.Typeflag { + case tar.TypeDir: + err = os.MkdirAll(dst, mode) + case tar.TypeLink: + err = os.Symlink(path.Join(dir, path.Clean(hdr.Linkname)), dst) + case tar.TypeReg: + var f io.WriteCloser + f, err = os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, mode) + if err != nil { + break + } + + _, err = io.Copy(f, t) + if err != nil && !errors.Is(err, io.EOF) { + break + } + err = f.Close() + } + + if err != nil { + return "", err + } + } + + return dir, nil +} diff --git a/benchmark/offliner/README.md b/benchmark/offliner/README.md new file mode 100644 index 000000000..0b24bbb2d --- /dev/null +++ b/benchmark/offliner/README.md @@ -0,0 +1,8 @@ +# Offliner + +A tool to offline, i.e. place all data for an container image in a remote +registry to a local data directory. This local data directory can be mounted to +docker.io/registry container registry so running against it eliminates remote +network access. + +Use: `offliner ` diff --git a/benchmark/offliner/base_images.go b/benchmark/offliner/base_images.go new file mode 100644 index 000000000..d64d09646 --- /dev/null +++ b/benchmark/offliner/base_images.go @@ -0,0 +1,133 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "encoding/json" + "strconv" + + "github.com/CycloneDX/cyclonedx-go" + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/spdx/tools-golang/spdx" +) + +func baseImages(ref name.Reference) ([]name.Reference, error) { + sbomRef := digestTag(ref, "sbom") + + img, err := remote.Image(sbomRef) + if err != nil { + return nil, err + } + + refs := make([]name.Reference, 0, 5) + layers, err := img.Layers() + if err != nil { + return nil, err + } + + fromCycloneDX := func(layer v1.Layer) ([]name.Reference, error) { + var refs = make([]name.Reference, 0, 5) + + data, err := layer.Uncompressed() + if err != nil { + return nil, err + } + defer data.Close() + + decoder := cyclonedx.NewBOMDecoder(data, cyclonedx.BOMFileFormatJSON) + + var bom cyclonedx.BOM + if err := decoder.Decode(&bom); err != nil { + return nil, err + } + + isNumber := func(s string) bool { + _, err := strconv.ParseUint(s, 10, 64) + return err == nil + } + + for _, formulation := range nab(bom.Formulation) { + for _, component := range nab(formulation.Components) { + if component.Type != cyclonedx.ComponentTypeContainer { + continue + } + + for _, property := range nab(component.Properties) { + isBase := property.Name == "konflux:container:is_base_image" && property.Value == "true" + isStage := property.Name == "konflux:container:is_builder_image:for_stage" && isNumber(property.Value) + if !isBase && !isStage { + continue + } + + if r, err := name.ParseReference(component.Name); err == nil { + refs = append(refs, r) + } + } + } + } + + return refs, nil + } + + fromSPDX := func(layer v1.Layer) ([]name.Reference, error) { + var refs = make([]name.Reference, 0, 5) + + data, err := layer.Uncompressed() + if err != nil { + return nil, err + } + defer data.Close() + + decoder := json.NewDecoder(data) + + var bom spdx.Document + if err := decoder.Decode(&bom); err != nil { + return nil, err + } + + // TODO missing the rest of the implementation here, lacking SPDX + // examples currently. Missing parsing and extracting base images from + // SPDX, similarly to how it is done for CycloneDX + + return refs, nil + } + + for _, layer := range layers { + mt, err := layer.MediaType() + if err != nil { + return nil, err + } + + var fetch func(v1.Layer) ([]name.Reference, error) = func(l v1.Layer) ([]name.Reference, error) { return nil, nil } + switch mt { + case "application/vnd.cyclonedx+json": + fetch = fromCycloneDX + case "text/spdx+json": + fetch = fromSPDX + } + + if more, err := fetch(layer); err != nil { + return nil, err + } else { + refs = append(refs, more...) + } + } + + return refs, nil +} diff --git a/benchmark/offliner/nab.go b/benchmark/offliner/nab.go new file mode 100644 index 000000000..947f71d37 --- /dev/null +++ b/benchmark/offliner/nab.go @@ -0,0 +1,25 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +func nab[T any](v *[]T) []T { + if v == nil { + return nil + } + + return *v +} diff --git a/benchmark/offliner/offliner.go b/benchmark/offliner/offliner.go new file mode 100644 index 000000000..6a129cc07 --- /dev/null +++ b/benchmark/offliner/offliner.go @@ -0,0 +1,139 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "context" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/docker/docker/api/types/container" + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/logs" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/modules/registry" +) + +func items(sourceImages []name.Reference, destination name.Registry) map[string]string { + items := map[string]string{} + for _, sourceImage := range sourceImages { + var dest fmt.Stringer = destination.Repo(sourceImage.Context().RepositoryStr()) + if d, ok := sourceImage.(name.Digest); ok { + dest = dest.(name.Repository).Digest(d.DigestStr()) + } + if t, ok := sourceImage.(name.Tag); ok { + dest = dest.(name.Repository).Tag(t.TagStr()) + } + + items[sourceImage.String()] = dest.String() + } + + return items +} + +func main() { + if len(os.Args) != 3 { + fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) + os.Exit(1) + } + + sourceImage := os.Args[1] + dir, err := filepath.Abs(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, 0755); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(3) + } + } + + source, err := name.ParseReference(sourceImage) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(4) + } + + _, ok := source.(name.Digest) + if !ok { + fmt.Fprintln(os.Stderr, "use pinned image references") + os.Exit(5) + } + + ctx := context.Background() + registry, err := registry.Run(ctx, + registry.DefaultImage, + testcontainers.WithConfigModifier(func(config *container.Config) { + config.User = fmt.Sprintf("%d:%d", os.Getuid(), os.Getgid()) + }), + testcontainers.WithHostConfigModifier(func(hostConfig *container.HostConfig) { + hostConfig.UsernsMode = "host" + hostConfig.Binds = append(hostConfig.Binds, fmt.Sprintf("%s:/var/lib/registry:z", dir)) + }), + ) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(6) + } + defer func() { _ = registry.Terminate(ctx) }() + + destination, err := name.NewRegistry(registry.RegistryName, name.Insecure) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(7) + } + logs.Progress = log.New(os.Stdout, "", log.LstdFlags) + + relatedImages, err := related(source) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(8) + } + + idx, err := remote.Index(source) + if err == nil { + idxManifest, err := idx.IndexManifest() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(8) + } + + for _, m := range idxManifest.Manifests { + img := source.Context().Digest(m.Digest.String()) + rel, err := related(img) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(9) + } + relatedImages = append(relatedImages, rel...) + } + } + + for s, d := range items(relatedImages, destination) { + if err := crane.Copy(s, d); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(10) + } + } +} diff --git a/benchmark/offliner/offliner_test.go b/benchmark/offliner/offliner_test.go new file mode 100644 index 000000000..c1e777ba2 --- /dev/null +++ b/benchmark/offliner/offliner_test.go @@ -0,0 +1,49 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "maps" + "testing" + + "github.com/google/go-containerregistry/pkg/name" +) + +func TestItems(t *testing.T) { + dest, err := name.NewRegistry("newregistry.io") + if err != nil { + t.Fatal(err) + } + + imgs := []name.Reference{ + name.MustParseReference("registry.io/repository/image"), + name.MustParseReference("registry.io/repository/image:tag"), + name.MustParseReference("registry.io/repository/image@sha256:9f80b4f7506d2799298a685162723482cac160abf701e029ee5cbaa6c74967ea"), + } + + got := items(imgs, dest) + + expected := map[string]string{ + "registry.io/repository/image": "newregistry.io/repository/image:latest", + "registry.io/repository/image:tag": "newregistry.io/repository/image:tag", + "registry.io/repository/image@sha256:9f80b4f7506d2799298a685162723482cac160abf701e029ee5cbaa6c74967ea": "newregistry.io/repository/image@sha256:9f80b4f7506d2799298a685162723482cac160abf701e029ee5cbaa6c74967ea", + } + + if !maps.Equal(expected, got) { + t.Errorf("expected and got images differ: %v != %v", expected, got) + } +} diff --git a/benchmark/offliner/referrers.go b/benchmark/offliner/referrers.go new file mode 100644 index 000000000..f182670ff --- /dev/null +++ b/benchmark/offliner/referrers.go @@ -0,0 +1,63 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" +) + +func referrers(ref name.Reference) ([]name.Reference, error) { + var err error + var idx v1.ImageIndex + if d, ok := ref.(name.Digest); ok { + idx, err = remote.Referrers(d) + + if err != nil { + return nil, err + } + } else { + img, err := remote.Image(ref) + if err != nil { + return nil, err + } + + digest, err := img.Digest() + if err != nil { + return nil, err + } + ref := ref.Context().Digest(digest.String()) + idx, err = remote.Referrers(ref) + if err != nil { + return nil, err + } + } + + indexManifest, err := idx.IndexManifest() + if err != nil { + return nil, err + } + + references := make([]name.Reference, 0, len(indexManifest.Manifests)) + for _, manifest := range indexManifest.Manifests { + r := ref.Context().Digest(manifest.Digest.String()) + references = append(references, r) + } + + return references, nil +} diff --git a/benchmark/offliner/refs.go b/benchmark/offliner/refs.go new file mode 100644 index 000000000..190530bf4 --- /dev/null +++ b/benchmark/offliner/refs.go @@ -0,0 +1,44 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "fmt" + "strings" + + "github.com/google/go-containerregistry/pkg/name" +) + +func digestTag(ref name.Reference, suffix string) name.Reference { + digest := ref.(name.Digest).DigestStr() + + tag := fmt.Sprintf("%s.%s", strings.Replace(digest, ":", "-", 1), suffix) + + return ref.Context().Tag(tag) +} + +func signature(ref name.Reference) name.Reference { + return digestTag(ref, "sig") +} + +func attestation(ref name.Reference) name.Reference { + return digestTag(ref, "att") +} + +func sbom(ref name.Reference) name.Reference { + return digestTag(ref, "sbom") +} diff --git a/benchmark/offliner/related.go b/benchmark/offliner/related.go new file mode 100644 index 000000000..f7260fdde --- /dev/null +++ b/benchmark/offliner/related.go @@ -0,0 +1,91 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "log" + "slices" + "strings" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" +) + +type relatedFn func(ref name.Reference) ([]name.Reference, error) + +func related(ref name.Reference) ([]name.Reference, error) { + references := []name.Reference{ref} + + for _, r := range []name.Reference{ + signature(ref), + attestation(ref), + sbom(ref), + } { + if _, err := remote.Image(r); err == nil { + references = append(references, r) + } else { + log.Printf("Can't dereference %q: %v", r, err) + } + } + + related := []relatedFn{ + referrers, + baseImages, + scanReports, + subjects, + } + + for _, rel := range related { + refs, err := rel(ref) + if err != nil { + log.Printf("Can't fetch related image for %q: %v", ref, err) + continue + } + references = append(references, refs...) + } + + cmp := func(a, b name.Reference) int { + return strings.Compare(a.String(), b.String()) + } + + for _, ref := range references { + if _, ok := ref.(name.Digest); !ok { + img, err := remote.Image(ref) + if err != nil { + return nil, err + } + + digest, err := img.Digest() + if err != nil { + return nil, err + } + + ref = ref.Context().Digest(digest.String()) + } + + ref := signature(ref) + if _, err := remote.Image(ref); err == nil { + references = append(references, ref) + } else { + log.Printf("Can't dereference %q: %v", ref, err) + } + } + + slices.SortFunc(references, cmp) + + return slices.Compact(references), nil +} diff --git a/benchmark/offliner/scans.go b/benchmark/offliner/scans.go new file mode 100644 index 000000000..c864d5552 --- /dev/null +++ b/benchmark/offliner/scans.go @@ -0,0 +1,117 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "encoding/base64" + "encoding/json" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/in-toto/in-toto-golang/in_toto" + "github.com/secure-systems-lab/go-securesystemslib/dsse" +) + +func scanReports(ref name.Reference) ([]name.Reference, error) { + att := attestation(ref) + + img, err := remote.Image(att) + if err != nil { + return nil, err + } + + layers, err := img.Layers() + if err != nil { + return nil, err + } + + refs := make([]name.Reference, 0, 5) + for _, layer := range layers { + if mt, err := layer.MediaType(); err != nil || mt != "application/vnd.dsse.envelope.v1+json" { + continue + } + + data, err := layer.Uncompressed() + if err != nil { + return nil, err + } + defer data.Close() + + var envelope dsse.Envelope + decoder := json.NewDecoder(data) + if err := decoder.Decode(&envelope); err != nil { + return nil, err + } + + if envelope.PayloadType != "application/vnd.in-toto+json" { + continue + } + + raw, err := base64.StdEncoding.DecodeString(envelope.Payload) + if err != nil { + return nil, err + } + + var statement in_toto.ProvenanceStatementSLSA02 + if err := json.Unmarshal(raw, &statement); err != nil { + return nil, err + } + + if statement.PredicateType != "https://slsa.dev/provenance/v0.2" { + continue + } + + subject, err := name.NewRepository(statement.Subject[0].Name) + if err != nil { + return nil, err + } + + buildConfig := statement.Predicate.BuildConfig + + tasks := buildConfig.(map[string]any)["tasks"].([]any) + + for _, task := range tasks { + task := task.(map[string]any) + // TODO match by reference instead of name + if task["name"] != "clair-scan" { + continue + } + + results := task["results"].([]any) + + for _, result := range results { + result := result.(map[string]any) + if result["name"] != "REPORTS" { + continue + } + + report := result["value"] + + var reports map[string]string + if err := json.Unmarshal([]byte(report.(string)), &reports); err != nil { + return nil, err + } + + for _, digest := range reports { + refs = append(refs, subject.Digest(digest)) + } + } + } + } + + return refs, nil +} diff --git a/benchmark/offliner/subjects.go b/benchmark/offliner/subjects.go new file mode 100644 index 000000000..8d9f2317e --- /dev/null +++ b/benchmark/offliner/subjects.go @@ -0,0 +1,90 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/in-toto/in-toto-golang/in_toto" + "github.com/secure-systems-lab/go-securesystemslib/dsse" +) + +func subjects(ref name.Reference) ([]name.Reference, error) { + att := attestation(ref) + + img, err := remote.Image(att) + if err != nil { + return nil, err + } + + layers, err := img.Layers() + if err != nil { + return nil, err + } + + refs := make([]name.Reference, 0, 5) + for _, layer := range layers { + if mt, err := layer.MediaType(); err != nil || mt != "application/vnd.dsse.envelope.v1+json" { + continue + } + + data, err := layer.Uncompressed() + if err != nil { + return nil, err + } + defer data.Close() + + var envelope dsse.Envelope + decoder := json.NewDecoder(data) + if err := decoder.Decode(&envelope); err != nil { + return nil, err + } + + if envelope.PayloadType != "application/vnd.in-toto+json" { + continue + } + + raw, err := base64.StdEncoding.DecodeString(envelope.Payload) + if err != nil { + return nil, err + } + + var statement in_toto.ProvenanceStatementSLSA02 + if err := json.Unmarshal(raw, &statement); err != nil { + return nil, err + } + + if statement.PredicateType != "https://slsa.dev/provenance/v0.2" { + continue + } + + for _, subject := range statement.Subject { + ref, err := name.NewRepository(subject.Name) + if err != nil { + return nil, err + } + refs = append(refs, ref.Digest(fmt.Sprintf("sha256:%s", subject.Digest["sha256"]))) + } + + } + + return refs, nil +} diff --git a/benchmark/simple/.gitattributes b/benchmark/simple/.gitattributes new file mode 100644 index 000000000..f6bd2897d --- /dev/null +++ b/benchmark/simple/.gitattributes @@ -0,0 +1 @@ +data.tar.gz filter=lfs diff=lfs merge=lfs -text diff --git a/benchmark/simple/data.tar.gz b/benchmark/simple/data.tar.gz new file mode 100644 index 000000000..fa4932b99 --- /dev/null +++ b/benchmark/simple/data.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d2212522089577e2162f5a5840e61e428fe37fa0dd96eba781c8f0570c00b88 +size 786216070 diff --git a/benchmark/simple/prepare_data.sh b/benchmark/simple/prepare_data.sh new file mode 100755 index 000000000..a710d65f9 --- /dev/null +++ b/benchmark/simple/prepare_data.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Copyright The Enterprise Contract Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Creates the files in the data directory that should contain all the data +# needed to run the benchmark, uses the ../offliner for images andplain git +# clone for the git data dependency +set -o errexit +set -o nounset +set -o pipefail + +offliner="$(git rev-parse --show-toplevel)/benchmark/offliner" + +dir="$(mktemp -d)" +trap 'rm -rf "${dir}"' EXIT + +( + cd "${dir}" + + imgs=( + quay.io/redhat-user-workloads/rhtap-contract-tenant/golden-container/golden-container@sha256:166e38c156fa81d577a7ba7a948b68c79005a06e302779d1bebc7d31e8bea315 + quay.io/konflux-ci/tekton-catalog/data-acceptable-bundles@sha256:1e70b8f672388838f20a7d45e145e31e99dab06cefa1c5514d6ce41c8bbea1b0 + quay.io/enterprise-contract/ec-release-policy@sha256:faed14fcf1a00cc19d6e71040219d232a6549e28167650e03ff4ca3204a73a24 + ) + + for img in "${imgs[@]}"; do + go run -C "${offliner}" . "${img}" "${dir}/data/registry/data" + done + + git clone --no-checkout https://github.com/release-engineering/rhtap-ec-policy.git data/git/rhtap-ec-policy.git +) + +tar czf data.tar.gz -C "${dir}" . diff --git a/benchmark/simple/simple.go b/benchmark/simple/simple.go new file mode 100644 index 000000000..789925243 --- /dev/null +++ b/benchmark/simple/simple.go @@ -0,0 +1,123 @@ +// Copyright The Enterprise Contract Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +// Simple benchmark running the @redhat collection policy at a fixed point in +// time with the state of the container image registry contained within the +// data/registry and git state within data/git. The prepare_data.sh script can +// be used to re-populate the data directory. +package main + +import ( + "fmt" + "os" + "path" + + "golang.org/x/benchmarks/driver" + + "github.com/enterprise-contract/ec-cli/benchmark/internal/registry" + "github.com/enterprise-contract/ec-cli/benchmark/internal/suite" + "github.com/enterprise-contract/ec-cli/benchmark/internal/untar" +) + +func main() { + driver.Main("Simple", benchmark) +} + +func setup() (string, suite.Closer) { + dir, err := untar.UnTar("data.tar.gz") + if err != nil { + panic(err) + } + + closer, err := registry.Launch(path.Join(dir, "data/registry/data")) + if err != nil { + panic(err) + } + + return dir, func() { + closer() + os.RemoveAll(dir) + } +} + +func benchmark() driver.Result { + dir, closer := setup() + defer closer() + + return driver.Benchmark(run(dir)) +} + +func ec(dir string) func() { + snapshot := `{ +"components": [ +{ + "name": "golden-container", + "containerImage": "quay.io/redhat-user-workloads/rhtap-contract-tenant/golden-container/golden-container@sha256:166e38c156fa81d577a7ba7a948b68c79005a06e302779d1bebc7d31e8bea315", + "source": { + "git": { + "url": "https://github.com/enterprise-contract/golden-container", + "revision": "8327c1ce7472b017b9396fe26d5d5e1ed0eb61cc" + } + } +} +] +}` + + policy := fmt.Sprintf(`{ +"publicKey": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZP/0htjhVt2y0ohjgtIIgICOtQtA\nnaYJRuLprwIv6FDhZ5yFjYUEtsmoNcW7rx2KM6FOXGsCX3BNc7qhHELT+g==\n-----END PUBLIC KEY-----", +"sources": [ +{ + "data": [ + "git::file://%s/data/git/rhtap-ec-policy.git//data?ref=a524ee2f2f7774f6f360eb64c4cb24004de52aae", + "oci::quay.io/konflux-ci/tekton-catalog/data-acceptable-bundles@sha256:1e70b8f672388838f20a7d45e145e31e99dab06cefa1c5514d6ce41c8bbea1b0" + ], + "policy": [ + "oci::quay.io/enterprise-contract/ec-release-policy@sha256:faed14fcf1a00cc19d6e71040219d232a6549e28167650e03ff4ca3204a73a24" + ], + "config": { + "include": [ + "@redhat" + ], + }, +} +] +}`, dir) + + return func() { + + os.Setenv("EC_CACHE", "false") + + if err := suite.Execute([]string{ + "validate", + "image", + "--json-input", + snapshot, + "--policy", + policy, + "--ignore-rekor", + "--effective-time", + "2024-12-10T00:00:00Z", + }); err != nil { + panic(err) + } + } +} + +func run(dir string) func(n uint64) { + return func(n uint64) { + driver.Parallel(n, 1, ec(dir)) + } +} diff --git a/cmd/root.go b/cmd/root.go index 1ce92a82d..ce0aca7a2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -20,6 +20,7 @@ import ( "context" log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" "github.com/enterprise-contract/ec-cli/cmd/fetch" "github.com/enterprise-contract/ec-cli/cmd/initialize" @@ -51,15 +52,19 @@ func Execute() { } func init() { - RootCmd.AddCommand(fetch.FetchCmd) - RootCmd.AddCommand(initialize.InitCmd) - RootCmd.AddCommand(inspect.InspectCmd) - RootCmd.AddCommand(track.TrackCmd) - RootCmd.AddCommand(validate.ValidateCmd) - RootCmd.AddCommand(version.VersionCmd) - RootCmd.AddCommand(opa.OPACmd) - RootCmd.AddCommand(sigstore.SigstoreCmd) + AddCommandsTo(RootCmd) +} + +func AddCommandsTo(cmd *cobra.Command) { + cmd.AddCommand(fetch.FetchCmd) + cmd.AddCommand(initialize.InitCmd) + cmd.AddCommand(inspect.InspectCmd) + cmd.AddCommand(track.TrackCmd) + cmd.AddCommand(validate.ValidateCmd) + cmd.AddCommand(version.VersionCmd) + cmd.AddCommand(opa.OPACmd) + cmd.AddCommand(sigstore.SigstoreCmd) if utils.Experimental() { - RootCmd.AddCommand(test.TestCmd) + cmd.AddCommand(test.TestCmd) } } diff --git a/go.mod b/go.mod index 011f49c35..b2e23db71 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,10 @@ go 1.22.7 require ( cuelang.org/go v0.11.0 + github.com/CycloneDX/cyclonedx-go v0.9.0 github.com/MakeNowJust/heredoc v1.0.0 github.com/Maldris/go-billy-afero v0.0.0-20200815120323-e9d3de59c99a + github.com/docker/docker v27.1.1+incompatible github.com/enterprise-contract/enterprise-contract-controller/api v0.1.69 github.com/enterprise-contract/go-gather v0.0.5 github.com/evanphx/json-patch v5.9.0+incompatible @@ -14,6 +16,7 @@ require ( github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.20.2 + github.com/google/safearchive v0.0.0-20241025131057-f7ce9d7b6f9c github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b github.com/hashicorp/go-getter v1.7.6 github.com/in-toto/in-toto-golang v0.9.0 @@ -31,6 +34,8 @@ require ( github.com/sigstore/cosign/v2 v2.4.1 github.com/sigstore/sigstore v1.8.9 github.com/sirupsen/logrus v1.9.3 + github.com/smarty/cproxy/v2 v2.1.1 + github.com/spdx/tools-golang v0.5.5 github.com/spf13/afero v1.11.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 @@ -38,6 +43,9 @@ require ( github.com/stretchr/testify v1.10.0 github.com/stuart-warren/yamlfmt v0.2.0 github.com/tektoncd/pipeline v0.63.0 + github.com/testcontainers/testcontainers-go v0.34.1-0.20241204123437-72be13940122 + github.com/testcontainers/testcontainers-go/modules/registry v0.34.0 + golang.org/x/benchmarks v0.0.0-20241115175113-a2b48b605b42 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/net v0.32.0 golang.org/x/sync v0.10.0 @@ -67,6 +75,7 @@ require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.15.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.29 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect @@ -76,7 +85,6 @@ require ( github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/BurntSushi/toml v1.4.0 // indirect - github.com/CycloneDX/cyclonedx-go v0.9.0 // indirect github.com/KeisukeYamashita/go-vcl v0.4.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect @@ -141,6 +149,7 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/typeurl/v2 v2.2.0 // indirect github.com/coreos/go-oidc/v3 v3.11.0 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect github.com/cyphar/filepath-securejoin v0.3.4 // indirect @@ -150,9 +159,11 @@ require ( github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v27.2.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect @@ -173,6 +184,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -226,6 +238,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/letsencrypt/boulder v0.0.0-20240830194243-1fcf0ee08180 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/maruel/natural v1.1.1 // indirect @@ -237,8 +250,14 @@ require ( github.com/moby/buildkit v0.15.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/locker v1.0.1 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.3.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/mozillazg/docker-credential-acr-helper v0.4.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect @@ -252,6 +271,7 @@ require ( github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.58.0 // indirect @@ -267,6 +287,8 @@ require ( github.com/segmentio/ksuid v1.0.4 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect + github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shteou/go-ignore v0.3.1 // indirect github.com/sigstore/fulcio v1.6.3 // indirect github.com/sigstore/protobuf-specs v0.3.2 // indirect @@ -275,7 +297,6 @@ require ( github.com/skeema/knownhosts v1.3.0 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spdx/tools-golang v0.5.5 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -290,6 +311,8 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/tmccombs/hcl2json v0.6.4 // indirect github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect @@ -301,6 +324,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zclconf/go-cty v1.15.0 // indirect go.mongodb.org/mongo-driver v1.16.1 // indirect go.opencensus.io v0.24.0 // indirect @@ -319,11 +343,11 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/mod v0.21.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.7.0 // indirect + golang.org/x/time v0.8.0 // indirect golang.org/x/tools v0.26.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.196.0 // indirect diff --git a/go.sum b/go.sum index 66babd806..50976b4c9 100644 --- a/go.sum +++ b/go.sum @@ -222,6 +222,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0/go.mod h1:qLIye2hwb/ZouqhpSD9Zn3SJipvpEnz1Ywl3VUk9Y0s= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= @@ -493,11 +495,15 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM= github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8= @@ -526,12 +532,18 @@ github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1G github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v27.2.0+incompatible h1:yHD1QEB1/0vr5eBNpu8tncu8gWxg8EydFPOSKHzXSMM= github.com/docker/cli v27.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -631,6 +643,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= @@ -778,11 +792,13 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs= +github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/safearchive v0.0.0-20241025131057-f7ce9d7b6f9c h1:GzqKebXGmQ+9RUwNUCjt768fVW0mMkSjw+BTR7wlyLQ= +github.com/google/safearchive v0.0.0-20241025131057-f7ce9d7b6f9c/go.mod h1:OqnQPv70Lm5prPo201C0t0krFmSjwgcWIAsA9S0xdQA= github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/trillian v1.6.0 h1:jMBeDBIkINFvS2n6oV5maDqfRlxREAc6CW9QYWQ0qT4= @@ -951,6 +967,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -1002,10 +1020,18 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g= github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1013,6 +1039,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mozillazg/docker-credential-acr-helper v0.4.0 h1:Uoh3Z9CcpEDnLiozDx+D7oDgRq7X+R296vAqAumnOcw= github.com/mozillazg/docker-credential-acr-helper v0.4.0/go.mod h1:2kiicb3OlPytmlNC9XGkLvVC+f0qTiJw3f/mhmeeQBg= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -1085,6 +1113,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1162,6 +1192,12 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shteou/go-ignore v0.3.1 h1:/DVY4w06eKliWrbkwKfBHJgUleld+QAlmlQvfRQOigA= github.com/shteou/go-ignore v0.3.1/go.mod h1:hMVyBe+qt5/Z11W/Fxxf86b5SuL8kM29xNWLYob9Vos= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -1204,6 +1240,12 @@ github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:s github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY= +github.com/smarty/assertions v1.16.0/go.mod h1:duaaFdCS0K9dnoM50iyek/eYINOZ64gbh1Xlf6LG7AI= +github.com/smarty/cproxy/v2 v2.1.1 h1:CReH/eZaK/YEQbWHYaoYFTtXFwjZCggqWrNLC5d46vE= +github.com/smarty/cproxy/v2 v2.1.1/go.mod h1:YzpKMSNNMlkkPUCeAnCLKJtjOwlYqQET7ZF3DFHEQ3g= +github.com/smarty/gunit v1.5.0 h1:OmG6a/rgi7qCjlQis6VjXbvx/WqZ8I6xSlbfN4YB5MY= +github.com/smarty/gunit v1.5.0/go.mod h1:uAeNibUD292KZRcg5OTy7lb6WR5++UC0BQOzNuiRzpU= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1278,6 +1320,12 @@ github.com/tektoncd/pipeline v0.63.0 h1:QLkhYr970jgs6vmHopXz8pcXbz5c3i0a0FX7ggGt github.com/tektoncd/pipeline v0.63.0/go.mod h1:HA7r0XJzhhcajNBcl0GErmcT5Omow1jVfLKwbVGjojY= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= +github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= +github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= +github.com/testcontainers/testcontainers-go v0.34.1-0.20241204123437-72be13940122 h1:dsnk0a/bMsSQzsfrFCvXkbp9arGuAVgike7POsCRXOg= +github.com/testcontainers/testcontainers-go v0.34.1-0.20241204123437-72be13940122/go.mod h1:wJduyVyIhQzkHwN3OZlrCQDygQpC3VNQEKewxc4c058= +github.com/testcontainers/testcontainers-go/modules/registry v0.34.0 h1:ooSrochnpOleRvr1/uOirSi+5Zjk9udmG7mkoQKmdEQ= +github.com/testcontainers/testcontainers-go/modules/registry v0.34.0/go.mod h1:lVn5G9wnfLV4N1WPdCtPUV9zlGbJvqyidSlojZLOBVA= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= @@ -1299,6 +1347,10 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHT github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmccombs/hcl2json v0.6.4 h1:/FWnzS9JCuyZ4MNwrG4vMrFrzRgsWEOVi+1AyYUVLGw= github.com/tmccombs/hcl2json v0.6.4/go.mod h1:+ppKlIW3H5nsAsZddXPy2iMyvld3SHxyjswOZhavRDk= github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 h1:2f304B10LaZdB8kkVEaoXvAMVan2tl9AiK4G0odjQtE= @@ -1345,6 +1397,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms= github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= @@ -1383,6 +1437,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrT go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= @@ -1408,6 +1464,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/benchmarks v0.0.0-20241115175113-a2b48b605b42 h1:BzkGQzHX30kNxg8pXCGB6nzRQhf7EkzvW+PIFMPu4mI= +golang.org/x/benchmarks v0.0.0-20241115175113-a2b48b605b42/go.mod h1:ffJO46aE6lfIXB1/kHNFyBOmsVj/KyOMziH9Cxj4uEE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1565,8 +1623,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1603,6 +1661,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1630,6 +1689,7 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w 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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1678,6 +1738,7 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1714,8 +1775,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2048,8 +2109,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=