diff --git a/.bingo/.gitignore b/.bingo/.gitignore new file mode 100644 index 000000000..9efccf683 --- /dev/null +++ b/.bingo/.gitignore @@ -0,0 +1,13 @@ + +# Ignore everything +* + +# But not these files: +!.gitignore +!*.mod +!*.sum +!README.md +!Variables.mk +!variables.env + +*tmp.mod diff --git a/.bingo/README.md b/.bingo/README.md new file mode 100644 index 000000000..7a5c2d4f6 --- /dev/null +++ b/.bingo/README.md @@ -0,0 +1,14 @@ +# Project Development Dependencies. + +This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo. + +* Run `bingo get` to install all tools having each own module file in this directory. +* Run `bingo get <tool>` to install <tool> that have own module file in this directory. +* For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $(<upper case tool name>) variable where <tool> is the .bingo/<tool>.mod. +* For shell: Run `source .bingo/variables.env` to source all environment variable for each tool. +* For go: Import `.bingo/variables.go` to for variable names. +* See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies. + +## Requirements + +* Go 1.14+ diff --git a/.bingo/Variables.mk b/.bingo/Variables.mk new file mode 100644 index 000000000..a4753b600 --- /dev/null +++ b/.bingo/Variables.mk @@ -0,0 +1,49 @@ +# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.9. DO NOT EDIT. +# All tools are designed to be build inside $GOBIN. +BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +GOPATH ?= $(shell go env GOPATH) +GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin +GO ?= $(shell which go) + +# Below generated variables ensure that every time a tool under each variable is invoked, the correct version +# will be used; reinstalling only if needed. +# For example for bingo variable: +# +# In your main Makefile (for non array binaries): +# +#include .bingo/Variables.mk # Assuming -dir was set to .bingo . +# +#command: $(BINGO) +# @echo "Running bingo" +# @$(BINGO) <flags/args..> +# +BINGO := $(GOBIN)/bingo-v0.9.0 +$(BINGO): $(BINGO_DIR)/bingo.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/bingo-v0.9.0" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=bingo.mod -o=$(GOBIN)/bingo-v0.9.0 "github.com/bwplotka/bingo" + +GINKGO := $(GOBIN)/ginkgo-v2.22.2 +$(GINKGO): $(BINGO_DIR)/ginkgo.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/ginkgo-v2.22.2" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=ginkgo.mod -o=$(GOBIN)/ginkgo-v2.22.2 "github.com/onsi/ginkgo/v2/ginkgo" + +GOLANGCI_LINT := $(GOBIN)/golangci-lint-v1.63.4 +$(GOLANGCI_LINT): $(BINGO_DIR)/golangci-lint.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/golangci-lint-v1.63.4" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=golangci-lint.mod -o=$(GOBIN)/golangci-lint-v1.63.4 "github.com/golangci/golangci-lint/cmd/golangci-lint" + +GORELEASER := $(GOBIN)/goreleaser-v1.26.2 +$(GORELEASER): $(BINGO_DIR)/goreleaser.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/goreleaser-v1.26.2" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=goreleaser.mod -o=$(GOBIN)/goreleaser-v1.26.2 "github.com/goreleaser/goreleaser" + +PROTOC_GEN_GO_GRPC := $(GOBIN)/protoc-gen-go-grpc-v1.3.0 +$(PROTOC_GEN_GO_GRPC): $(BINGO_DIR)/protoc-gen-go-grpc.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/protoc-gen-go-grpc-v1.3.0" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=protoc-gen-go-grpc.mod -o=$(GOBIN)/protoc-gen-go-grpc-v1.3.0 "google.golang.org/grpc/cmd/protoc-gen-go-grpc" + diff --git a/.bingo/bingo.mod b/.bingo/bingo.mod new file mode 100644 index 000000000..e7fa8545f --- /dev/null +++ b/.bingo/bingo.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.22.2 + +require github.com/bwplotka/bingo v0.9.0 diff --git a/.bingo/bingo.sum b/.bingo/bingo.sum new file mode 100644 index 000000000..f231dd11b --- /dev/null +++ b/.bingo/bingo.sum @@ -0,0 +1,29 @@ +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/bwplotka/bingo v0.9.0 h1:slnsdJYExR4iRalHR6/ZiYnr9vSazOuFGmc2LdX293g= +github.com/bwplotka/bingo v0.9.0/go.mod h1:GxC/y/xbmOK5P29cn+B3HuOSw0s2gruddT3r+rDizDw= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/efficientgo/core v1.0.0-rc.0 h1:jJoA0N+C4/knWYVZ6GrdHOtDyrg8Y/TR4vFpTaqTsqs= +github.com/efficientgo/core v1.0.0-rc.0/go.mod h1:kQa0V74HNYMfuJH6jiPiwNdpWXl4xd/K4tzlrcvYDQI= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= +mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= diff --git a/.bingo/ginkgo.mod b/.bingo/ginkgo.mod new file mode 100644 index 000000000..c1e0852df --- /dev/null +++ b/.bingo/ginkgo.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.22.2 + +require github.com/onsi/ginkgo/v2 v2.22.2 // ginkgo diff --git a/.bingo/ginkgo.sum b/.bingo/ginkgo.sum new file mode 100644 index 000000000..e2123cdc6 --- /dev/null +++ b/.bingo/ginkgo.sum @@ -0,0 +1,106 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= +github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/.bingo/go.mod b/.bingo/go.mod new file mode 100644 index 000000000..610249af0 --- /dev/null +++ b/.bingo/go.mod @@ -0,0 +1 @@ +module _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files. \ No newline at end of file diff --git a/.bingo/golangci-lint.mod b/.bingo/golangci-lint.mod new file mode 100644 index 000000000..8104ff4ba --- /dev/null +++ b/.bingo/golangci-lint.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.22.5 + +require github.com/golangci/golangci-lint v1.63.4 // cmd/golangci-lint diff --git a/.bingo/golangci-lint.sum b/.bingo/golangci-lint.sum new file mode 100644 index 000000000..bcc2ba2df --- /dev/null +++ b/.bingo/golangci-lint.sum @@ -0,0 +1,1071 @@ +4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= +github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= +github.com/4meepo/tagalign v1.4.1 h1:GYTu2FaPGOGb/xJalcqHeD4il5BiCywyEYZOA55P6J4= +github.com/4meepo/tagalign v1.4.1/go.mod h1:2H9Yu6sZ67hmuraFgfZkNcg5Py9Ch/Om9l2K/2W1qS4= +github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY= +github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM= +github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE= +github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw= +github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM= +github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= +github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA= +github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI= +github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ= +github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= +github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs= +github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0= +github.com/Antonboom/testifylint v1.4.3 h1:ohMt6AHuHgttaQ1xb6SSnxCeK4/rnK7KKzbvs7DmEck= +github.com/Antonboom/testifylint v1.4.3/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA= +github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk= +github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= +github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA= +github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74= +github.com/Crocmagnon/fatcontext v0.5.3 h1:zCh/wjc9oyeF+Gmp+V60wetm8ph2tlsxocgg/J0hOps= +github.com/Crocmagnon/fatcontext v0.5.3/go.mod h1:XoCQYY1J+XTfyv74qLXvNw4xFunr3L1wkopIIKG7wGM= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= +github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= +github.com/alecthomas/go-check-sumtype v0.1.4 h1:WCvlB3l5Vq5dZQTFmodqL2g68uHiSwwlWcT5a2FGK0c= +github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= +github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= +github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexkohler/nakedret/v2 v2.0.4 h1:yZuKmjqGi0pSmjGpOC016LtPJysIL0WEUiaXW5SUnNg= +github.com/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= +github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU= +github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= +github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= +github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/alingse/nilnesserr v0.1.1 h1:7cYuJewpy9jFNMEA72Q1+3Nm3zKHzg+Q28D5f2bBFUA= +github.com/alingse/nilnesserr v0.1.1/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= +github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= +github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= +github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= +github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU= +github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= +github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= +github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= +github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= +github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw= +github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= +github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A= +github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc= +github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= +github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= +github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs= +github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos= +github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA= +github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= +github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk= +github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8= +github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= +github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= +github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY= +github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M= +github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= +github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= +github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= +github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= +github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc= +github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= +github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= +github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= +github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= +github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/ckaznocha/intrange v0.2.0 h1:FykcZuJ8BD7oX93YbO1UY9oZtkRbp+1/kJcDjkefYLs= +github.com/ckaznocha/intrange v0.2.0/go.mod h1:r5I7nUlAAG56xmkOpw4XVr16BXhwYTUdcuRFeevn1oE= +github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY= +github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo= +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/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= +github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= +github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= +github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= +github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= +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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= +github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= +github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= +github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk= +github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw= +github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY= +github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA= +github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU= +github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc= +github.com/go-critic/go-critic v0.11.5 h1:TkDTOn5v7EEngMxu8KbuFqFR43USaaH8XRJLz1jhVYA= +github.com/go-critic/go-critic v0.11.5/go.mod h1:wu6U7ny9PiaHaZHcvMDmdysMqvDem162Rh3zWTrqk8M= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= +github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= +github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= +github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU= +github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= +github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME= +github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE= +github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9 h1:t5wybL6RtO83VwoMOb7U/Peqe3gGKQlPIC66wXmnkvM= +github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9/go.mod h1:Ag3L7sh7E28qAp/5xnpMMTuGYqxLZoSaEHZDkZB1RgU= +github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8= +github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8= +github.com/golangci/golangci-lint v1.63.4 h1:bJQFQ3hSfUto597dkL7ipDzOxsGEpiWdLiZ359OWOBI= +github.com/golangci/golangci-lint v1.63.4/go.mod h1:Hx0B7Lg5/NXbaOHem8+KU+ZUIzMI6zNj/7tFwdnn10I= +github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= +github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= +github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= +github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= +github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= +github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= +github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs= +github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +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= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= +github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= +github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= +github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= +github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk= +github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA= +github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc= +github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= +github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= +github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= +github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos= +github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= +github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0= +github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= +github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg= +github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= +github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= +github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= +github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= +github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4QqyxXmng8I= +github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0= +github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= +github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= +github.com/ldez/exptostd v0.3.1 h1:90yWWoAKMFHeovTK8uzBms9Ppp8Du/xQ20DRO26Ymrw= +github.com/ldez/exptostd v0.3.1/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ= +github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= +github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= +github.com/ldez/gomoddirectives v0.6.0 h1:Jyf1ZdTeiIB4dd+2n4qw+g4aI9IJ6JyfOZ8BityWvnA= +github.com/ldez/gomoddirectives v0.6.0/go.mod h1:TuwOGYoPAoENDWQpe8DMqEm5nIfjrxZXmxX/CExWyZ4= +github.com/ldez/grignotin v0.7.0 h1:vh0dI32WhHaq6LLPZ38g7WxXuZ1+RzyrJ7iPG9JMa8c= +github.com/ldez/grignotin v0.7.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk= +github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= +github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk= +github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I= +github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA= +github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ= +github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= +github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= +github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= +github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A= +github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU= +github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M= +github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= +github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= +github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= +github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.16.2 h1:8iLqHIZvN4fTLDC0Ke9tbSZVcyVHoBs0HIbnVSxfHJk= +github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ= +github.com/nunnatsa/ginkgolinter v0.18.4 h1:zmX4KUR+6fk/vhUFt8DOP6KwznekhkmVSzzVJve2vyM= +github.com/nunnatsa/ginkgolinter v0.18.4/go.mod h1:AMEane4QQ6JwFz5GgjI5xLUM9S/CylO+UyM97fN2iBI= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY= +github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw= +github.com/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU= +github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo= +github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= +github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= +github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU= +github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE= +github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= +github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= +github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= +github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= +github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI= +github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= +github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ= +github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= +github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyEl3M= +github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU= +github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk= +github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= +github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0= +github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY= +github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY= +github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw= +github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= +github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM= +github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c= +github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= +github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= +github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4= +github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= +github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= +github.com/tdakkota/asciicheck v0.3.0 h1:LqDGgZdholxZMaJgpM6b0U9CFIjDCbFdUF00bDnBKOQ= +github.com/tdakkota/asciicheck v0.3.0/go.mod h1:KoJKXuX/Z/lt6XzLo8WMBfQGzak0SrAKZlvRr4tg8Ac= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs= +github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tetafro/godot v1.4.20 h1:z/p8Ek55UdNvzt4TFn2zx2KscpW4rWqcnUrdmvWJj7E= +github.com/tetafro/godot v1.4.20/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg= +github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= +github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= +github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= +github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg= +github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= +github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4= +github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg= +github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= +github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= +github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= +github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= +github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ= +github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= +github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g= +github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= +github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM= +github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U= +github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA= +github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= +github.com/uudashr/iface v1.3.0 h1:zwPch0fs9tdh9BmL5kcgSpvnObV+yHjO4JjVBl8IA10= +github.com/uudashr/iface v1.3.0/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg= +github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= +github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= +github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= +github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= +github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= +github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= +gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= +go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs= +go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM= +go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE= +go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM= +go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY= +go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f h1:WTyX8eCCyfdqiPYkRGm0MqElSfYFH3yR1+rl/mct9sA= +golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +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= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +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/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= +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= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= +honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= +mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU= +mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo= +mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= +mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/.bingo/goreleaser.mod b/.bingo/goreleaser.mod new file mode 100644 index 000000000..f9b0b721b --- /dev/null +++ b/.bingo/goreleaser.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.22.2 + +require github.com/goreleaser/goreleaser v1.26.2 diff --git a/.bingo/goreleaser.sum b/.bingo/goreleaser.sum new file mode 100644 index 000000000..0034e5452 --- /dev/null +++ b/.bingo/goreleaser.sum @@ -0,0 +1,1769 @@ +bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.82.0/go.mod h1:vlKccHJGuFBFufnAnuB08dfEH9Y3H7dzDzRECFdC2TA= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY= +cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.0 h1:QDB2MZHqjTt0hGKnoEWyG/iWykue/lvkLdogLgrg10U= +cloud.google.com/go v0.94.0/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.5.0/go.mod h1:c4nNYR1qdq7eaZ+jSc5fonrQN2k3M7sWATcYTiakjEo= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v0.1.0 h1:VXAb5OzejDcyhFzIDeZ5n5AUdlsFnCyexuascIwWMj0= +cloud.google.com/go/kms v0.1.0/go.mod h1:8Qp8PCAypHg4FdmlyW1QRAv09BGQ9Uzh7JnmIZxPk+c= +cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= +cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= +cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.16.0/go.mod h1:6A8EfoWZ/lUvCWStKGwAWauJZSiuV0Mkmu6WilK/TxQ= +cloud.google.com/go/secretmanager v0.1.0/go.mod h1:3nGKHvnzDUVit7U0S9KAKJ4aOsO1xtwRG+7ey5LK1bM= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.16.1 h1:sMEIc4wxvoY3NXG7Rn9iP7jb/2buJgWR1vNXCR/UPfs= +cloud.google.com/go/storage v1.16.1/go.mod h1:LaNorbty3ehnU3rEjXSNV/NRgQA0O8Y+uh6bPe5UOk4= +cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= +cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= +cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g= +code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= +code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= +code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +code.gitea.io/sdk/gitea v0.18.0 h1:+zZrwVmujIrgobt6wVBWCqITz6bn1aBjnCUHmpZrerI= +code.gitea.io/sdk/gitea v0.18.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI= +contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= +contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ= +contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= +github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= +github.com/Azure/azure-amqp-common-go/v3 v3.1.0/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0= +github.com/Azure/azure-amqp-common-go/v3 v3.1.1/go.mod h1:YsDaPfaO9Ub2XeSKdIy2DfwuiQlHQCauHJwSqtrkECI= +github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= +github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= +github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v57.0.0+incompatible h1:isVki3PbIFrwKvKdVP1byxo73/pt+Nn174YxW1k4PNw= +github.com/Azure/azure-sdk-for-go v57.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 h1:fXPMAmuh0gDuRDey0atC8cXBuKIlqCzCkL8sm1n9Ov0= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4= +github.com/Azure/azure-service-bus-go v0.10.16/go.mod h1:MlkLwGGf1ewcx5jZadn0gUEty+tTg0RaElr6bPf+QhI= +github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM= +github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck= +github.com/Azure/go-amqp v0.13.0/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1xlxUTs= +github.com/Azure/go-amqp v0.13.11/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk= +github.com/Azure/go-amqp v0.13.12/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk= +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.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.20 h1:s8H1PbCZSqg/DH7JMlOz6YMig6htWLNPsjDdlLqCx3M= +github.com/Azure/go-autorest/autorest v0.11.20/go.mod h1:o3tqFY+QR40VOlk+pV4d77mORO64jOXSgEnPQgLK6JY= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.15 h1:X+p2GF0GWyOiSmqohIaEeuNFNDY4I4EOlVuUQvFdWMk= +github.com/Azure/go-autorest/autorest/adal v0.9.15/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= +github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 h1:TzPg6B6fTZ0G1zBf3T54aI7p3cAT6u//TOXGPmFMOXg= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.3 h1:DOhB+nXkF7LN0JfBGB5YtCF6QLK8mLe4psaHF7ZQEKM= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.3/go.mod h1:yAQ2b6eP/CmLPnmLvxtT1ALIY3OR1oFcCqVBi8vHiTc= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DisgoOrg/disgohook v1.4.4 h1:6xU+nRtyCYX7RyKvRnroJE8JMv+YIrQEMBDGUjBGDlQ= +github.com/DisgoOrg/disgohook v1.4.4/go.mod h1:l7r9dZgfkA3KiV+ErxqweKaknnskmzZO+SRTNHvJTUU= +github.com/DisgoOrg/log v1.1.0 h1:a6hLfVSDuTFJc5AKQ8FDYQ5TASnwk3tciUyXThm1CR4= +github.com/DisgoOrg/log v1.1.0/go.mod h1:Qihgz6fax3JCfuO7vxVavL0LyHS0sUdQ9OmykQ2fiQs= +github.com/DisgoOrg/restclient v1.2.8 h1:0Kv2g2bNYUvAAeIpJ1oNHorRcj5z6qkO2kOlm4R7cAs= +github.com/DisgoOrg/restclient v1.2.8/go.mod h1:2pc/htya/5kjxvWNYya98sb8B4mexobxmWvhTiWPt94= +github.com/GoogleCloudPlatform/cloudsql-proxy v1.24.0/go.mod h1:3tx938GhY4FC+E1KT/jNjDw7Z5qxAEtIiERJ2sXjnII= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c h1:bNpaLLv2Y4kslsdkdCwAYu8Bak1aGVtxwi8Z/wy4Yuo= +github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1 h1:6mZ7MG/flSahicBVy4GKlWI+dzoR5rgnm7H8e17TAio= +github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/anchore/bubbly v0.0.0-20230518153401-87b6af8ccf22 h1:5NFK6VGgqBUOAX2SYyzFYvNdOiYDxzim8jga386FlZY= +github.com/anchore/bubbly v0.0.0-20230518153401-87b6af8ccf22/go.mod h1:Kv+Mm9CdtnV8iem48iEPIwy7/N4Wmk0hpxYNH5gTwKQ= +github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw= +github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg= +github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU= +github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb/go.mod h1:DmTY2Mfcv38hsHbG78xMiTDdxFtkHpgYNVDPsF2TgHk= +github.com/anchore/quill v0.4.1 h1:mffDnvnER3ZgPjN5hexc3nr/4Y1dtKdDB6td5K8uInk= +github.com/anchore/quill v0.4.1/go.mod h1:t6hOPYDohN8wn2SRWQdNkJBkhmK8s3gzuHzzgcEvzQU= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= +github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= +github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/atc0005/go-teams-notify/v2 v2.6.1 h1:t22ybzQuaQs4UJe4ceF5VYGsPhs6ir3nZOId/FBy6Go= +github.com/atc0005/go-teams-notify/v2 v2.6.1/go.mod h1:xo6GejLDHn3tWBA181F8LrllIL0xC1uRsRxq7YNXaaY= +github.com/atc0005/go-teams-notify/v2 v2.10.0 h1:eQvRIkyESQgBvlUdQ/iPol/lj3QcRyrdEQM3+c/nXhM= +github.com/atc0005/go-teams-notify/v2 v2.10.0/go.mod h1:SIeE1UfCcVRYMqP5b+r1ZteHyA/2UAjzWF5COnZ8q0w= +github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.40.34 h1:SBYmodndE2d4AYucuuJnOXk4MD1SFbucoIdpwKVKeSA= +github.com/aws/aws-sdk-go v1.40.34/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.53.0 h1:MMo1x1ggPPxDfHMXJnQudTbGXYlD4UigUAud1DJxPVo= +github.com/aws/aws-sdk-go v1.53.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.9.0 h1:+S+dSqQCN3MSU5vJRu1HqHrq00cJn6heIMU7X9hcsoo= +github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= +github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo= +github.com/aws/aws-sdk-go-v2/config v1.7.0 h1:J2cZ7qe+3IpqBEXnHUrFrOjoB9BlsXg7j53vxcl5IVg= +github.com/aws/aws-sdk-go-v2/config v1.7.0/go.mod h1:w9+nMZ7soXCe5nT46Ri354SNhXDQ6v+V5wqDjnZE+GY= +github.com/aws/aws-sdk-go-v2/config v1.27.13 h1:WbKW8hOzrWoOA/+35S5okqO/2Ap8hkkFUzoW8Hzq24A= +github.com/aws/aws-sdk-go-v2/config v1.27.13/go.mod h1:XLiyiTMnguytjRER7u5RIkhIqS8Nyz41SwAWb4xEjxs= +github.com/aws/aws-sdk-go-v2/credentials v1.4.0 h1:kmvesfjY861FzlCU9mvAfe01D9aeXcG2ZuC+k9F2YLM= +github.com/aws/aws-sdk-go-v2/credentials v1.4.0/go.mod h1:dgGR+Qq7Wjcd4AOAW5Rf5Tnv3+x7ed6kETXyS9WCuAY= +github.com/aws/aws-sdk-go-v2/credentials v1.17.13 h1:XDCJDzk/u5cN7Aple7D/MiAhx1Rjo/0nueJ0La8mRuE= +github.com/aws/aws-sdk-go-v2/credentials v1.17.13/go.mod h1:FMNcjQrmuBYvOTZDtOLCIu0esmxjF7RuA/89iSXWzQI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0 h1:OxTAgH8Y4BXHD6PGCJ8DHx2kaZPCQfSTqmDsdRZFezE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0/go.mod h1:CpNzHK9VEFUCknu50kkB8z58AH2B5DvPP7ea1LHve/Y= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9 h1:vXY/Hq1XdxHBIYgBUmug/AbMyIe1AKulPYS2/VE1X70= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9/go.mod h1:GyJJTZoHVuENM4TeJEl5Ffs4W9m19u+4wKJcDi/GZ4A= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2 h1:d95cddM3yTm4qffj3P6EnP+TzX1SSkWaQypXSgT/hpA= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2/go.mod h1:BQV0agm+JEhqR+2RT5e1XTFIDcAAV0eW6z2trp+iduw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3 h1:mDnFOE2sVkyphMWtTH+stv0eW3k0OTx94K63xpxHty4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3/go.mod h1:V8MuRVcCRt5h1S+Fwu8KbC7l/gBGo3yBAyUbJM2IJOk= +github.com/aws/aws-sdk-go-v2/service/ecr v1.28.0 h1:rdPrcOZmqT2F+yzmKEImrx5XUs7Hpf4V9Rp6E8mhsxQ= +github.com/aws/aws-sdk-go-v2/service/ecr v1.28.0/go.mod h1:if7ybzzjOmDB8pat9FE35AHTY6ZxlYSy3YviSmFZv8c= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.5 h1:452e/nFuqPvwPg+1OD2CG/v29R9MH8egJSJKh2Qduv8= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.5/go.mod h1:8pvvNAklmq+hKmqyvFoMRg0bwg9sdGOvdwximmKiKP0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5 h1:mbWNpfRUTT6bnacmvOTKXZjR/HycibdWzNpfbrbLDIs= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5/go.mod h1:FCOPWGjsshkkICJIn9hq9xr6dLKtyaWpuUojiN3W1/8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0 h1:VNJ5NLBteVXEwE2F1zEXVmyIH58mZ6kIQGJoC7C+vkg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0/go.mod h1:R1KK+vY8AfalhG1AOu5e35pOD2SdoPKQCFLTvnxiohk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3 h1:4t+QEX7BsXz98W8W1lNvMAG+NX8qHz2CjLBxQKku40g= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3/go.mod h1:oFcjjUq5Hm09N9rpxTdeMeLeQcxS7mIkBkL8qUKng+A= +github.com/aws/aws-sdk-go-v2/service/kms v1.5.0 h1:10e9mzaaYIIePEuxUzW5YJ8LKHNG/NX63evcvS3ux9U= +github.com/aws/aws-sdk-go-v2/service/kms v1.5.0/go.mod h1:w7JuP9Oq1IKMFQPkNe3V6s9rOssXzOVEMNEqK1L1bao= +github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= +github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= +github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4 h1:lW5xUzOPGAMY7HPuNF4FdyBwRc3UJ/e8KsapbesVeNU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4/go.mod h1:MGTaf3x/+z7ZGugCGvepnx2DS6+caCYYqKhzVoLNYPk= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.6.0/go.mod h1:B+7C5UKdVq1ylkI/A6O8wcurFtaux0R1njePNPtKwoA= +github.com/aws/aws-sdk-go-v2/service/ssm v1.10.0/go.mod h1:4dXS5YNqI3SNbetQ7X7vfsMlX6ZnboJA2dulBwJx7+g= +github.com/aws/aws-sdk-go-v2/service/sso v1.4.0 h1:sHXMIKYS6YiLPzmKSvDpPmOpJDHxmAUgbiF49YNVztg= +github.com/aws/aws-sdk-go-v2/service/sso v1.4.0/go.mod h1:+1fpWnL96DL23aXPpMGbsmKe8jLTEfbjuQoA4WS1VaA= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.6 h1:o5cTaeunSpfXiLTIBx5xo2enQmiChtu1IBbzXnfU9Hs= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.6/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.0 h1:Qe0r0lVURDDeBQJ4yP+BOrJkvkiCo/3FH/t+wY11dmw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.0/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= +github.com/aws/aws-sdk-go-v2/service/sts v1.7.0 h1:1at4e5P+lvHNl2nUktdM2/v+rpICg/QSEr9TO/uW9vU= +github.com/aws/aws-sdk-go-v2/service/sts v1.7.0/go.mod h1:0qcSMCyASQPN2sk/1KQLQ2Fh6yq8wm0HSDAimPhzCoM= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.7 h1:et3Ta53gotFR4ERLXXHIHl/Uuk1qYpP5uU7cvNql8ns= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.7/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw= +github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240514230400-03fa26f5508f h1:Z0kS9pJDQgCg3u2lH6+CdYaFbyQtyukVTiUCG6re0E4= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240514230400-03fa26f5508f/go.mod h1:rAE739ssmE5O5fLuQ2y8uHdmOJaelE5I0Es3SxV0y1A= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blacktop/go-dwarf v1.0.9 h1:eT/L7gt0gllvvgnRXY0MFKjNB6+jtOY5DTm2ynVX2dY= +github.com/blacktop/go-dwarf v1.0.9/go.mod h1:4W2FKgSFYcZLDwnR7k+apv5i3nrau4NGl9N6VQ9DSTo= +github.com/blacktop/go-macho v1.1.162 h1:FjM3XAsJTAOGZ1eppRSX9ZBX3Bk11JMTC1amsZAOA5I= +github.com/blacktop/go-macho v1.1.162/go.mod h1:f2X4noFBob4G5bWUrzvPBKDVcFWZgDCM7rIn7ygTID0= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= +github.com/bluesky-social/indigo v0.0.0-20240411170459-440932307e0d h1:xxPhzCOpmOntzVe8S6tqsMdFgaB8B4NXSV54lG4B1qk= +github.com/bluesky-social/indigo v0.0.0-20240411170459-440932307e0d/go.mod h1:ysMQ0a4RYWjgyvKrl5ME352oHA6QgK900g5sB9XXgPE= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw= +github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= +github.com/caarlos0/ctrlc v1.2.0 h1:AtbThhmbeYx1WW3WXdWrd94EHKi+0NPRGS4/4pzrjwk= +github.com/caarlos0/ctrlc v1.2.0/go.mod h1:n3gDlSjsXZ7rbD9/RprIR040b7oaLfNStikPd4gFago= +github.com/caarlos0/env/v11 v11.0.1 h1:A8dDt9Ub9ybqRSUF3fQc/TA/gTam2bKT4Pit+cwrsPs= +github.com/caarlos0/env/v11 v11.0.1/go.mod h1:2RC3HQu8BQqtEK3V4iHPxj0jOdWdbPpWJ6pOueeU1xM= +github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k= +github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= +github.com/caarlos0/go-reddit/v3 v3.0.1 h1:w8ugvsrHhaE/m4ez0BO/sTBOBWI9WZTjG7VTecHnql4= +github.com/caarlos0/go-reddit/v3 v3.0.1/go.mod h1:QlwgmG5SAqxMeQvg/A2dD1x9cIZCO56BMnMdjXLoisI= +github.com/caarlos0/go-shellwords v1.0.12 h1:HWrUnu6lGbWfrDcFiHcZiwOLzHWjjrPVehULaTFgPp8= +github.com/caarlos0/go-shellwords v1.0.12/go.mod h1:bYeeX1GrTLPl5cAMYEzdm272qdsQAZiaHgeF0KTk1Gw= +github.com/caarlos0/go-version v0.1.1 h1:1bikKHkGGVIIxqCmufhSSs3hpBScgHGacrvsi8FuIfc= +github.com/caarlos0/go-version v0.1.1/go.mod h1:Ze5Qx4TsBBi5FyrSKVg1Ibc44KGV/llAaKGp86oTwZ0= +github.com/caarlos0/log v0.4.4 h1:LnvgBz/ofsJ00AupP/cEfksJSZglb1L69g4Obk/sdAc= +github.com/caarlos0/log v0.4.4/go.mod h1:+AmCI9Liv5LKXmzFmFI1htuHdTTj/0R3KuoP9DMY7Mo= +github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk= +github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc= +github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8= +github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= +github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/charmbracelet/bubbletea v0.22.1 h1:z66q0LWdJNOWEH9zadiAIXp2GN1AWrwNXU8obVY9X24= +github.com/charmbracelet/bubbletea v0.22.1/go.mod h1:8/7hVvbPN6ZZPkczLiB8YpLkLJ0n7DMho5Wvfd2X1C0= +github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= +github.com/charmbracelet/x/exp/ordered v0.0.0-20231010190216-1cb11efc897d h1:+o+e/8hf7cG0SbAzEAm/usJ8qoZPgFXhudLjop+TM0g= +github.com/charmbracelet/x/exp/ordered v0.0.0-20231010190216-1cb11efc897d/go.mod h1:aoG4bThKYIOnyB55r202eHqo6TkN7ZXV+cu4Do3eoBQ= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= +github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= +github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +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/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= +github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= +github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb h1:7ENzkH+O3juL+yj2undESLTaAeRllHwCs/b8z6aWSfc= +github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb/go.mod h1:qhZBgV9e4WyB1JNjHpcXVkUe3knWUwYuAPB1hITdm50= +github.com/dghubble/oauth1 v0.7.1 h1:JjbOVSVVkms9A4h/sTQy5Jb2nFuAAVb2qVYgenJPyrE= +github.com/dghubble/oauth1 v0.7.1/go.mod h1:0eEzON0UY/OLACQrmnjgJjmvCGXzjBCsZqL1kWDXtF0= +github.com/dghubble/oauth1 v0.7.3 h1:EkEM/zMDMp3zOsX2DC/ZQ2vnEX3ELK0/l9kb+vs4ptE= +github.com/dghubble/oauth1 v0.7.3/go.mod h1:oxTe+az9NSMIucDPDCCtzJGsPhciJV33xocHfcR2sVY= +github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY= +github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +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.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v25.0.4+incompatible h1:DatRkJ+nrFoYL2HZUzjM5Z5sAmcA5XGp+AW0oEw2+cA= +github.com/docker/cli v25.0.4+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 v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo= +github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= +github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +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.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk= +github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +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= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk= +github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= +github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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-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= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= +github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= +github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= +github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U= +github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc= +github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4= +github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= +github.com/google/go-replayers/httpreplay v1.0.0/go.mod h1:LJhKoTwS5Wy5Ld/peq8dFFG5OfJyHEz7ft+DsTUv25M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/ko v0.15.4 h1:0blRbIdPmSy6v4LvedGxbI/8krdJYQgbSih3v6Y8V1c= +github.com/google/ko v0.15.4/go.mod h1:ZkcmfV91Xt6ZzOBHc/cXXGYnqWdNWDVy/gHoUU9sjag= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +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= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +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-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e h1:6Jn9JtfCn20uycra92LxTkq5yfBKNSFlRJPBk8/Cxhg= +github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e/go.mod h1:83rLnx5vhPyN/mDzBYJWtiPf+9xnSVQynTpqZWe7OnY= +github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a h1:JJBdjSfqSy3mnDT0940ASQFghwcZ4y4cb6ttjAoXqwE= +github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= +github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/goreleaser/chglog v0.1.2 h1:tdzAb/ILeMnphzI9zQ7Nkq+T8R9qyXli8GydD8plFRY= +github.com/goreleaser/chglog v0.1.2/go.mod h1:tTZsFuSZK4epDXfjMkxzcGbrIOXprf0JFp47BjIr3B8= +github.com/goreleaser/chglog v0.6.1 h1:NZKiX8l0FTQPRzBgKST7knvNZmZ04f7PEGkN2wInfhE= +github.com/goreleaser/chglog v0.6.1/go.mod h1:Bnnfo07jMZkaAb0uRNASMZyOsX6ROW6X1qbXqN3guUo= +github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I= +github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU= +github.com/goreleaser/goreleaser v1.8.3 h1:4vP28LV1VOL+mtEVvejCkN6KD1OU++7YNCh9dojxcO0= +github.com/goreleaser/goreleaser v1.8.3/go.mod h1:DpiLDZkJQ1bbKW0ipWPJApOp8T4naqqk9nxyldGRy4k= +github.com/goreleaser/goreleaser v1.26.2 h1:1iY1HaXtRiMTrwy6KE1sNjkRjsjMi+9l0k6WUX8GpWw= +github.com/goreleaser/goreleaser v1.26.2/go.mod h1:mHi6zr6fuuOh5eHdWWgyo/N8BWED5WEVtb/4GETc9jQ= +github.com/goreleaser/nfpm/v2 v2.15.1 h1:OdscWscGNR4aBepj2S5p6JUHWFd3CJdTJlSq7UqMMTY= +github.com/goreleaser/nfpm/v2 v2.15.1/go.mod h1:fpR40o+Wq6aeE5xoSZY3E23r06aLntuYIr2zBCJ1x1o= +github.com/goreleaser/nfpm/v2 v2.37.1 h1:RUmeEt8OlEVeSzKRrO5Vl5qVWCtUwx4j9uivGuRo5fw= +github.com/goreleaser/nfpm/v2 v2.37.1/go.mod h1:q8+sZXFqn106/eGw+9V+I8+izFxZ/sJjrhwmEUxXhUg= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs= +github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA= +github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ= +github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= +github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw= +github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo= +github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= +github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= +github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs= +github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk= +github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= +github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= +github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o= +github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 h1:WGrKdjHtWC67RX96eTkYD2f53NDHhrq/7robWTAfk4s= +github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491/go.mod h1:o158RFmdEbYyIZmXAbrvmJWesbyxlLKee6X64VPVuOc= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= +github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-mastodon v0.0.8 h1:UgKs4SmQ5JeawxMIPP7NQ9xncmOXA+5q6jYk4erR7vk= +github.com/mattn/go-mastodon v0.0.8/go.mod h1:8YkqetHoAVEktRkK15qeiv/aaIMfJ/Gc89etisPZtHU= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA= +github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/coral v1.0.0 h1:odyqkoEg4aJAINOzvnjN4tUsdp+Zleccs7tRIAkkYzU= +github.com/muesli/coral v1.0.0/go.mod h1:bf91M/dkp7iHQw73HOoR9PekdTJMTD6ihJgWoDitde8= +github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= +github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= +github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbYvWg= +github.com/muesli/mango-cobra v1.2.0/go.mod h1:vMJL54QytZAJhCT13LPVDfkvCUJ5/4jNUKF/8NC2UjA= +github.com/muesli/mango-coral v1.0.1 h1:W3nGbUC/q5vLscQ6GPzteHZrJI1Msjw5Hns82o0xRkI= +github.com/muesli/mango-coral v1.0.1/go.mod h1:EPSlYH67AtcxQrxssNw6r/lMFxHTjuDoGfq9Uxxevhg= +github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg= +github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= +github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= +github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0= +github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= +github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA= +github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sigstore/cosign/v2 v2.2.4 h1:iY4vtEacmu2hkNj1Fh+8EBqBwKs2DHM27/lbNWDFJro= +github.com/sigstore/cosign/v2 v2.2.4/go.mod h1:JZlRD2uaEjVAvZ1XJ3QkkZJhTqSDVtLaet+C/TMR81Y= +github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8= +github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc= +github.com/sigstore/sigstore v1.8.3 h1:G7LVXqL+ekgYtYdksBks9B38dPoIsbscjQJX/MGWkA4= +github.com/sigstore/sigstore v1.8.3/go.mod h1:mqbTEariiGA94cn6G3xnDiV6BD8eSLdL/eA7bvJ0fVs= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/slack-go/slack v0.10.2 h1:KMN/h2sgUninHXvQI8PrR/PHBUuWp2NPvz2Kr66tki4= +github.com/slack-go/slack v0.10.2/go.mod h1:5FLdBRv7VW/d9EBxx/eEktOptWygbA9K2QK/KW7ds1s= +github.com/slack-go/slack v0.13.0 h1:7my/pR2ubZJ9912p9FtvALYpbt0cQPAqkRy2jaSI1PQ= +github.com/slack-go/slack v0.13.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= +github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= +github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +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/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= +github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA= +github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20= +github.com/wagoodman/go-progress v0.0.0-20220614130704-4b1c25a33c7c h1:gFwUKtkv6QzQsFdIjvPqd0Qdw42DHUEbbUdiUTI1uco= +github.com/wagoodman/go-progress v0.0.0-20220614130704-4b1c25a33c7c/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.1.1-0.20240311221002-68b9f235c302 h1:MhInbXe4SzcImAKktUvWBCWZgcw6MYf5NfumTj1BhAw= +github.com/whyrusleeping/cbor-gen v0.1.1-0.20240311221002-68b9f235c302/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= +github.com/xanzy/go-gitlab v0.63.0 h1:a9fXpKWykUS6dowapFej/2Wjf4aOAEFC1q2ZIcz4IpI= +github.com/xanzy/go-gitlab v0.63.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= +github.com/xanzy/go-gitlab v0.105.0 h1:3nyLq0ESez0crcaM19o5S//SvezOQguuIHZ3wgX64hM= +github.com/xanzy/go-gitlab v0.105.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= +github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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= +gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8= +gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +gocloud.dev v0.24.0 h1:cNtHD07zQQiv02OiwwDyVMuHmR7iQt2RLkzoAgz7wBs= +gocloud.dev v0.24.0/go.mod h1:uA+als++iBX5ShuG4upQo/3Zoz49iIPlYUWHV5mM8w8= +gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro= +gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco= +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-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU= +golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/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-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.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= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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-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= +golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/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-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210223095934-7937bea0104d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.4/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= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +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.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.52.0/go.mod h1:Him/adpjt0sxtkWViy0b6xyKW/SD71CwdJ7HqJo7SrU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0 h1:08F9XVYTLOGeSQb3xI9C0gXMuQanhdGed0cWFhDozbI= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk= +google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210517163617-5e0236093d7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210825212027-de86158e7fda/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= +google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= +google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 h1:oqta3O3AnlWbmIE3bFnWbu4bRxZjfbWCp0cKSuZh01E= +google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= +gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +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= +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= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/kind v0.23.0 h1:8fyDGWbWTeCcCTwA04v4Nfr45KKxbSPH1WO9K+jVrBg= +sigs.k8s.io/kind v0.23.0/go.mod h1:ZQ1iZuJLh3T+O8fzhdi3VWcFTzsdXtNv2ppsHc8JQ7s= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/.bingo/protoc-gen-go-grpc.mod b/.bingo/protoc-gen-go-grpc.mod new file mode 100644 index 000000000..51b100833 --- /dev/null +++ b/.bingo/protoc-gen-go-grpc.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.22.2 + +require google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 diff --git a/.bingo/protoc-gen-go-grpc.sum b/.bingo/protoc-gen-go-grpc.sum new file mode 100644 index 000000000..1f112872e --- /dev/null +++ b/.bingo/protoc-gen-go-grpc.sum @@ -0,0 +1,12 @@ +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/.bingo/variables.env b/.bingo/variables.env new file mode 100644 index 000000000..4f607b50d --- /dev/null +++ b/.bingo/variables.env @@ -0,0 +1,20 @@ +# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.9. DO NOT EDIT. +# All tools are designed to be build inside $GOBIN. +# Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk. +GOBIN=${GOBIN:=$(go env GOBIN)} + +if [ -z "$GOBIN" ]; then + GOBIN="$(go env GOPATH)/bin" +fi + + +BINGO="${GOBIN}/bingo-v0.9.0" + +GINKGO="${GOBIN}/ginkgo-v2.22.2" + +GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.63.4" + +GORELEASER="${GOBIN}/goreleaser-v1.26.2" + +PROTOC_GEN_GO_GRPC="${GOBIN}/protoc-gen-go-grpc-v1.3.0" + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..025457d21 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" + groups: + k8s-dependencies: + patterns: + - "k8s.io/*" + - "sigs.k8s.io/*" + golang-x-deps: + patterns: + - "golang.org/x/*" + - package-exosystem: "docker" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 000000000..1bd35d01d --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,19 @@ +name: build + +on: + push: + branches: + - '**' + pull_request: + paths: + - '**' + - '!doc/**' +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + - run: make build diff --git a/.github/workflows/go-apidiff.yaml b/.github/workflows/go-apidiff.yaml new file mode 100644 index 000000000..0b0c93942 --- /dev/null +++ b/.github/workflows/go-apidiff.yaml @@ -0,0 +1,28 @@ +name: go-apidiff + +on: + push: + branches: + - '**' + pull_request: + paths: + - '**' + - '!doc/**' + merge_group: + +jobs: + go-apidiff: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + id: go + - name: Run go-apidiff + uses: joelanford/go-apidiff@main diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml new file mode 100644 index 000000000..30bb9d313 --- /dev/null +++ b/.github/workflows/goreleaser.yaml @@ -0,0 +1,149 @@ +name: goreleaser +on: + push: + branches: + - 'master' + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + pull_request: {} + merge_group: +defaults: + run: + shell: bash +jobs: + release: + needs: + - build-windows + - build-darwin + - build-linux + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + + - run: | + for dist in dist-*; do + tar -C "${dist}" -xf "${dist}/${dist}.tar" + done + + - name: Create assets + run: | + set -xe + mkdir -p assets + cat dist-*/dist/checksums.txt > assets/checksums.txt + for asset in dist-*/dist/*_*/*; do + base=$(basename "${asset}") + variant=$(basename $(dirname "${asset}") | cut -d_ -f1) + cp "${asset}" "assets/${variant}-${base}" + done + find assets -ls + cat assets/checksums.txt + + - name: Upload Release Assets + if: github.ref_type == 'tag' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release create "${{ github.ref_name }}" --generate-notes ./assets/* + + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + with: + # GoReleaser requires fetch-depth: 0 to correctly + # run git describe + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + - name: "Run GoReleaser" + run: make release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_ARGS: release --skip=validate --clean -f release/goreleaser.windows.yaml ${{ github.event_name == 'pull_request' && '--snapshot' || '' }} + + - run: tar -cvf dist-windows.tar dist + - uses: actions/upload-artifact@v4 + with: + name: dist-windows + path: dist-windows.tar + + build-darwin: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + # GoReleaser requires fetch-depth: 0 to correctly + # run git describe + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + - name: "Run GoReleaser" + run: make release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_ARGS: release --rm-dist -f release/goreleaser.darwin.yaml --skip=validate ${{ github.event_name == 'pull_request' && '--snapshot' || '' }} + + - run: gtar -cvf dist-darwin.tar dist + - uses: actions/upload-artifact@v4 + with: + name: dist-darwin + path: dist-darwin.tar + + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # GoReleaser requires fetch-depth: 0 to correctly + # run git describe + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + - name: "Install linux cross-compilers" + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu gcc-s390x-linux-gnu gcc-powerpc64le-linux-gnu + + - name: "Set the image tag" + run: | + if [[ $GITHUB_REF == refs/tags/* ]]; then + # Release tags. + echo IMAGE_TAG="${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + elif [[ $GITHUB_REF == refs/heads/* ]]; then + # Branch build. + echo IMAGE_TAG="$(echo "${GITHUB_REF#refs/heads/}" | sed -r 's|/+|-|g')" >> $GITHUB_ENV + elif [[ $GITHUB_REF == refs/pull/* ]]; then + # PR build. + echo IMAGE_TAG="pr-$(echo "${GITHUB_REF}" | sed -E 's|refs/pull/([^/]+)/?.*|\1|')" >> $GITHUB_ENV + else + echo IMAGE_TAG="$(git describe --tags --always)" >> $GITHUB_ENV + fi + + - name: "Login to Quay" + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.QUAY_USERNAME }} + password: ${{ secrets.QUAY_PASSWORD }} + registry: quay.io + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: "Run GoReleaser" + run: make release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_ARGS: release --rm-dist -f release/goreleaser.linux.yaml --skip=validate ${{ github.event_name == 'pull_request' && '--snapshot' || '' }} + + - run: tar -cvf dist-linux.tar dist + - uses: actions/upload-artifact@v4 + with: + name: dist-linux + path: dist-linux.tar diff --git a/.github/workflows/sanity.yaml b/.github/workflows/sanity.yaml new file mode 100644 index 000000000..68d8b6d36 --- /dev/null +++ b/.github/workflows/sanity.yaml @@ -0,0 +1,24 @@ +name: sanity + +on: + push: + branches: + - '**' + pull_request: + paths: + - '**' + - '!doc/**' + merge_group: + +jobs: + sanity: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + - name: Install goimports + run: go install golang.org/x/tools/cmd/goimports@latest + - name: Run verify checks + run: make verify diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..a353509cf --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,31 @@ +name: test +on: + push: + branches: + - '**' + pull_request: + paths: + - '**' + - '!doc/**' + merge_group: + +jobs: + e2e: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + - name: Install podman + run: | + sudo apt-get update + sudo apt-get -y install podman + podman version + - name: Create kind cluster and setup local docker registry + run: | + "${GITHUB_WORKSPACE}/scripts/start_registry.sh" kind-registry + export DOCKER_REGISTRY_HOST=localhost:443 + - name: Run e2e tests + run: | + KUBECONFIG="$HOME/.kube/config" DOCKER_REGISTRY_HOST=localhost:443 make build e2e CLUSTER=kind diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml new file mode 100644 index 000000000..26634c6a2 --- /dev/null +++ b/.github/workflows/unit.yaml @@ -0,0 +1,27 @@ +name: unit + +on: + push: + branches: + - '**' + pull_request: + paths: + - '**' + - '!doc/**' + merge_group: + +jobs: + unit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + - run: make unit + - run: sed -i'' "s:^github.com/$GITHUB_REPOSITORY/::" coverage.out + - uses: codecov/codecov-action@v5 + with: + disable_search: true + files: coverage.out + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index fc9b43fb2..e36468cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -179,10 +179,7 @@ tags *.userprefs # Build results -[Dd]ebug/ [Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ x64/ x86/ bld/ @@ -461,3 +458,21 @@ pkg/apprclient/openapi/git_push.sh !pkg/**/testdata/** !test/**testdata/** +/coverage.out + +# Test artifacts generated by e2e +test/e2e/bundle.Dockerfile +test/e2e/downloaded/** +test/e2e/opm-* +test/e2e/bundle_tmp* +test/e2e/index_tmp* + +# don't check in the certs directory +certs/* + +# ignore temp artifacts of building images +pkg/lib/indexer/index.Dockerfile* + +# ignore vendor since we don't commit it +vendor/* + diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 000000000..0bc5d1097 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,83 @@ +######## +# NOTE +# +# This file is duplicated in the following repos: +# - operator-framework/kubectl-operator +# - operator-framework/catalogd +# - operator-framework/operator-controller +# - operator-framework/operator-registry +# +# If you are making a change, please make it in ALL +# of the above repositories! +# +# TODO: Find a way to have a shared golangci config. +######## + +run: + # Default timeout is 1m, up to give more room + timeout: 4m + +linters: + enable: + - asciicheck + - bodyclose + - errorlint + - gci + - gofmt + - govet + - gosec + - importas + - misspell + - nestif + - nonamedreturns + - prealloc + - stylecheck + - testifylint + - tparallel + - unconvert + - unparam + - unused + - whitespace + +linters-settings: + gci: + sections: + - standard + - dot + - default + - prefix(github.com/operator-framework) + - localmodule + custom-order: true + + errorlint: + errorf: false + + importas: + alias: + - pkg: k8s.io/apimachinery/pkg/apis/meta/v1 + alias: metav1 + - pkg: k8s.io/apimachinery/pkg/api/errors + alias: apierrors + - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 + alias: apiextensionsv1 + - pkg: k8s.io/apimachinery/pkg/util/runtime + alias: utilruntime + - pkg: "^k8s\\.io/api/([^/]+)/(v[^/]+)$" + alias: $1$2 + - pkg: sigs.k8s.io/controller-runtime + alias: ctrl + - pkg: github.com/blang/semver/v4 + alias: bsemver + +issues: + # exclusion rules, mostly to avoid functionally complete areas and reduce unit test noise + exclude-rules: + - path: _test\.go + linters: + - unused + - govet + + +output: + formats: + - format: tab diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 447c06cef..000000000 --- a/.travis.yml +++ /dev/null @@ -1,53 +0,0 @@ -language: go -go: -- 1.13 -jobs: - include: - - os: linux - dist: xenial - env: - MAKE: make - install: | - curl -sLo minikube "$(curl -sL https://api.github.com/repos/kubernetes/minikube/releases/latest | jq -r '[.assets[] | select(.name == "minikube-linux-amd64")] | first | .browser_download_url')" - chmod +x minikube - sudo mv minikube /bin/ - minikube config set vm-driver none - minikube config set kubernetes-version $(go list -f '{{.Version}}' -m k8s.io/api | sed 's/^v0\./v1./') - - os: osx - install: | - brew install make - env: - MAKE: make - - os: windows - env: - MAKE: mingw32-make -addons: - apt: - sources: - - sourceline: 'ppa:projectatomic/ppa' - update: true - packages: - - podman - - conntrack -script: | - "${MAKE}" unit build - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - sudo minikube start # vm-driver=none requires root - sudo chown -R "$USER" "$HOME/.kube" "$HOME/.minikube" - KUBECONFIG="$HOME/.kube/config" make e2e - fi -notifications: - email: false -before_deploy: -- ls bin | xargs -n1 -I{} mv bin/{} "bin/$(go env GOOS)-$(go env GOARCH)-{}" -deploy: - provider: releases - edge: true - token: - secure: 1mcUdIu9BBQloKWHEXIum9XFunDVDtWvbL5HuebsSJOlePTRnccBnhwwyxytkxO8bkWlB7RXRwa2JRKAOtrB2sgyvG4zthQeiyuq3qNRuZPyl/KxcHT5swYhwXaFy2kSmsG3WJy6Yx+Rw82yDelnyUkv2XcJODcU3Sf0CZIaYmCHmT9dFJ97yGd5x/Xbw+ApBIjRYQgL/NCXcvR/7ftIMUGcYc6zSMG9U6eWCvY28gZGhElvywbm51UuwOzK37jNKrp9xe4c+Fbp+7EqEUY4ooxCxX82PmJRDEcdjY0NLdafmPN40TA6oDB1873OEIWCa7+Lfn5k+X+JTcV/rPOfOIRB0vS04m5HWJONu4gNHB5lYl3DRHonbhF4X/hzkujlFGkWB/3XDwSj9X88McL0P7mwZsXV5KsiH7kqH3FTzlH2Fm3OTHhBOEJ1s+OEcwRlBRahh8LfzD6Da7BNncSWi2zdc7erD5WVmeiJngZXzGquo3Ly3GWB9Pfkd0rriclHC0CmIj5EeD7NBnrCu18dwdlKRR5L18dUmoLV1I/IUh0BIn0i7CNt3iw15LVX4Lk6wz2JzEfytGQ3GzfIf4cPjmGqIYwlOUuyiht7AyEUg3QIBiqTbU/PL+krvFhAtf3RkD7/5+NZF6VF4p4hYXJN0sGq3XOsN7Ol1nVvc6RpAlk= - file_glob: true - file: bin/**/*-opm - cleanup: false - on: - repo: operator-framework/operator-registry - tags: true diff --git a/DCO b/DCO new file mode 100644 index 000000000..8201f9921 --- /dev/null +++ b/DCO @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 6694eec47..000000000 --- a/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -FROM openshift/origin-release:golang-1.13 as builder - -RUN yum update -y && \ - yum install -y make git sqlite glibc-static openssl-static zlib-static && \ - yum groupinstall -y "Development Tools" "Development Libraries" - -ENV GOPATH /go -ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH - -WORKDIR /src - -COPY OPM_VERSION OPM_VERSION -COPY vendor vendor -COPY cmd cmd -COPY pkg pkg -COPY Makefile go.mod go.sum ./ -RUN make build - -# copy and build vendored grpc_health_probe -RUN mkdir -p /go/src/github.com/grpc-ecosystem && \ - cp -R vendor/github.com/grpc-ecosystem/grpc-health-probe /go/src/github.com/grpc-ecosystem/grpc_health_probe && \ - cp -R vendor/ /go/src/github.com/grpc-ecosystem/grpc_health_probe && \ - rm -rf /go/src/github.com/grpc-ecosystem/grpc_health_probe/vendor/github.com/grpc-ecosystem/grpc-health-probe && \ - cd /go/src/github.com/grpc-ecosystem/grpc_health_probe && \ - CGO_ENABLED=0 go install -a -tags netgo -ldflags "-w" - -FROM openshift/origin-base - -RUN mkdir /registry -WORKDIR /registry - -COPY --from=builder /src/bin/initializer /bin/initializer -COPY --from=builder /src/bin/registry-server /bin/registry-server -COPY --from=builder /src/bin/configmap-server /bin/configmap-server -COPY --from=builder /src/bin/appregistry-server /bin/appregistry-server -COPY --from=builder /src/bin/opm /bin/opm -COPY --from=builder /go/bin/grpc-health-probe /bin/grpc_health_probe - -RUN chgrp -R 0 /registry && \ - chmod -R g+rwx /registry - -# This image doesn't need to run as root user -USER 1001 - -EXPOSE 50051 - -ENTRYPOINT ["/bin/registry-server"] -CMD ["--database", "/bundles.db"] - -LABEL io.k8s.display-name="OpenShift Operator Registry" \ - io.k8s.description="This is a component of OpenShift Operator Lifecycle Manager and is the base for operator catalog API containers." \ - maintainer="Odin Team <aos-odin@redhat.com>" \ - summary="Operator Registry runs in a Kubernetes or OpenShift cluster to provide operator catalog data to Operator Lifecycle Manager." diff --git a/Makefile b/Makefile index 45126d29f..6ac2911ca 100644 --- a/Makefile +++ b/Makefile @@ -1,56 +1,123 @@ -GO := GOFLAGS="-mod=vendor" go +SHELL = /bin/bash +GO := go CMDS := $(addprefix bin/, $(shell ls ./cmd | grep -v opm)) OPM := $(addprefix bin/, opm) SPECIFIC_UNIT_TEST := $(if $(TEST),-run $(TEST),) -PKG := github.com/operator-framework/operator-registry -GIT_COMMIT := $(shell git rev-parse --short HEAD) -OPM_VERSION := $(shell cat OPM_VERSION) -BUILD_DATE := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') +SPECIFIC_SKIP_UNIT_TEST := $(if $(SKIP),-skip $(SKIP),) +extra_env := $(GOENV) +export PKG := github.com/operator-framework/operator-registry +export GIT_COMMIT := $(or $(SOURCE_GIT_COMMIT),$(shell git rev-parse --short HEAD)) +export OPM_VERSION := $(or $(SOURCE_GIT_TAG),$(shell git describe --always --tags HEAD)) +export BUILD_DATE := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') +.DEFAULT_GOAL := all + +# bingo manages consistent tooling versions for things like kind, kustomize, etc. +include .bingo/Variables.mk + +# protoc is not a go binary, so we need a custom recipe for it. +PROTOC := ./tools/bin/protoc +PROTOC_VERSION := 27.0 +.PHONY: $(PROTOC) +$(PROTOC): + ./scripts/ensure-protoc.sh $(PROTOC_VERSION) + +# define characters +null := +space := $(null) # +comma := , +# default to json1 for sqlite3 and containers_image_openpgp for containers/image +TAGS := json1,containers_image_openpgp + +# Cluster to use for e2e testing +CLUSTER ?= "" +ifeq ($(CLUSTER), kind) +# add kind to the list of tags +TAGS := $(TAGS),kind +endif + +# -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64 and windows/amd64 +ifeq ($(shell go env GOARCH),s390x) +TEST_RACE := +else +TEST_RACE := -race +endif .PHONY: all all: clean test build $(CMDS): - $(GO) build $(extra_flags) -o $@ ./cmd/$(notdir $@) + $(extra_env) $(GO) build $(extra_flags) -tags=$(TAGS) -o $@ ./cmd/$(notdir $@) + +.PHONY: $(OPM) $(OPM): opm_version_flags=-ldflags "-X '$(PKG)/cmd/opm/version.gitCommit=$(GIT_COMMIT)' -X '$(PKG)/cmd/opm/version.opmVersion=$(OPM_VERSION)' -X '$(PKG)/cmd/opm/version.buildDate=$(BUILD_DATE)'" $(OPM): - $(GO) build $(opm_version_flags) $(extra_flags) -o $@ ./cmd/$(notdir $@) + $(extra_env) $(GO) build $(opm_version_flags) $(extra_flags) -tags=$(TAGS) -o $@ ./cmd/$(notdir $@) .PHONY: build build: clean $(CMDS) $(OPM) +.PHONY: cross +cross: opm_version_flags=-ldflags "-X '$(PKG)/cmd/opm/version.gitCommit=$(GIT_COMMIT)' -X '$(PKG)/cmd/opm/version.opmVersion=$(OPM_VERSION)' -X '$(PKG)/cmd/opm/version.buildDate=$(BUILD_DATE)'" +cross: +ifeq ($(shell go env GOARCH),amd64) + GOOS=darwin CC=o64-clang CXX=o64-clang++ CGO_ENABLED=1 $(GO) build $(opm_version_flags) -tags=$(TAGS) -o "bin/darwin-amd64-opm" --ldflags "-extld=o64-clang" ./cmd/opm + GOOS=windows CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ CGO_ENABLED=1 $(GO) build $(opm_version_flags) -tags=$(TAGS) -o "bin/windows-amd64-opm" --ldflags "-extld=x86_64-w64-mingw32-gcc" -buildmode=exe ./cmd/opm +endif + .PHONY: static -static: extra_flags=-ldflags '-w -extldflags "-static"' +static: extra_flags=-ldflags '-w -extldflags "-static"' -tags "json1" static: build .PHONY: unit unit: - $(GO) test $(SPECIFIC_UNIT_TEST) -count=1 -v -race ./pkg/... + $(GO) test -coverprofile=coverage.out --coverpkg=./... $(SPECIFIC_UNIT_TEST) $(SPECIFIC_SKIP_UNIT_TEST) -tags=$(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/... + +.PHONY: tidy +tidy: + go mod tidy + go mod verify + +.PHONY: verify +verify: tidy codegen lint + git diff --exit-code + +.PHONY: sanity-check +sanity-check: + # Build a container with the most recent binaries for this project. + # Does not include the database, which needs to be added separately. + docker build -f upstream-builder.Dockerfile -t sanity-container . + + # TODO: add more invocations of the opm binary here + + # serve the container for a second, using the bundles.db in testdata + docker run --rm -it -v "$(shell pwd)"/pkg/lib/indexer/testdata/:/database sanity-container \ + ./bin/opm registry serve --database /database/bundles.db --timeout-seconds 1 -.PHONY: image -image: - docker build . .PHONY: image-upstream image-upstream: docker build -f upstream-example.Dockerfile . -.PHONY: vendor -vendor: - $(GO) mod vendor +.PHONY: lint +lint: $(GOLANGCI_LINT) + $(GOLANGCI_LINT) run --build-tags=$(TAGS) $(GOLANGCI_LINT_ARGS) -.PHONY: codegen -codegen: - protoc -I pkg/api/ --go_out=plugins=grpc:pkg/api pkg/api/*.proto - protoc -I pkg/api/grpc_health_v1 --go_out=plugins=grpc:pkg/api/grpc_health_v1 pkg/api/grpc_health_v1/*.proto +.PHONY: fix-lint +fix-lint: $(GOLANGCI_LINT) + $(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_ARGS) -.PHONY: container-codegen -container-codegen: - docker build -t operator-registry:codegen -f codegen.Dockerfile . - docker run --name temp-codegen operator-registry:codegen /bin/true - docker cp temp-codegen:/codegen/pkg/api/. ./pkg/api - docker rm temp-codegen +.PHONY: bingo-upgrade +bingo-upgrade: $(BINGO) #EXHELP Upgrade tools + @for pkg in $$($(BINGO) list | awk '{ print $$3 }' | tail -n +3 | sed 's/@.*//'); do \ + echo -e "Upgrading \033[35m$$pkg\033[0m to latest..."; \ + $(BINGO) get "$$pkg@latest"; \ + done + +.PHONY: codegen +codegen: $(PROTOC) $(PROTOC_GEN_GO_GRPC) + $(PROTOC) --plugin=protoc-gen-go=$(PROTOC_GEN_GO_GRPC) -I pkg/api/ --go_out=pkg/api pkg/api/*.proto + $(PROTOC) --plugin=protoc-gen-go-grpc=$(PROTOC_GEN_GO_GRPC) -I pkg/api/ --go-grpc_out=pkg/api pkg/api/*.proto .PHONY: generate-fakes generate-fakes: @@ -61,5 +128,57 @@ clean: @rm -rf ./bin .PHONY: e2e -e2e: - $(GO) run github.com/onsi/ginkgo/ginkgo --v --randomizeAllSpecs --randomizeSuites --race ./test/e2e +e2e: $(GINKGO) + $(GINKGO) --v --randomize-all --progress --trace --randomize-suites --race $(if $(TEST),-focus '$(TEST)') -tags=$(TAGS) ./test/e2e -- $(if $(SKIPTLS),-skip-tls-verify true) $(if $(USEHTTP),-use-http true) + +.PHONY: release +export OPM_IMAGE_REPO ?= quay.io/operator-framework/opm +export IMAGE_TAG ?= $(OPM_VERSION) +export MAJ_MIN_IMAGE_OR_EMPTY := $(call tagged-or-empty,$(shell echo $(OPM_VERSION) | grep -Eo 'v[0-9]+\.[0-9]+')) +export MAJ_IMAGE_OR_EMPTY := $(call tagged-or-empty,$(shell echo $(OPM_VERSION) | grep -Eo 'v[0-9]+')) +# LATEST_TAG is the latest semver tag in HEAD. Used to deduce whether +# OPM_VERSION is the new latest tag, or a prior minor/patch tag, below. +# NOTE: this can only be relied upon if full git history is present. +# An actions/checkout step must use "fetch-depth: 0", for example. +LATEST_TAG := $(shell git tag -l | tr - \~ | sort -V | tr \~ - | tail -n1) +# LATEST_IMAGE_OR_EMPTY is set to OPM_IMAGE_REPO:latest when OPM_VERSION +# is not a prerelase tag and == LATEST_TAG, otherwise the empty string. +# An empty string causes goreleaser to skip building the manifest image for latest, +# which we do not want when cutting a non-latest release (old minor/patch tag). +export LATEST_IMAGE_OR_EMPTY := $(shell \ + echo $(OPM_VERSION) | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$$' \ + && [ "$(shell echo -e "$(OPM_VERSION)\n$(LATEST_TAG)" | sort -rV | head -n1)" == "$(OPM_VERSION)" ] \ + && echo "$(OPM_IMAGE_REPO):latest" || echo "") +RELEASE_GOOS := $(shell go env GOOS) +RELEASE_ARGS ?= release --clean --snapshot -f release/goreleaser.$(RELEASE_GOOS).yaml + +# Note: bingo does not yet support windows (https://github.com/bwplotka/bingo/issues/26) +# so GOOS=windows gets its own way to install goreleaser +ifeq ($(RELEASE_GOOS), windows) +GORELEASER := $(shell pwd)/bin/goreleaser +release: windows-goreleaser-install +else +release: $(GORELEASER) +endif +release: + $(GORELEASER) $(RELEASE_ARGS) + +.PHONY: windows-goreleaser-install +windows-goreleaser-install: + # manually install goreleaser from the bingo directory in the same way bingo (currently) installs it. + # This is done to ensure the same version of goreleaser is used across all platforms + mkdir -p $(dir $(GORELEASER)) + @echo "(re)installing $(GORELEASER)" + GOWORK=off $(GO) build -mod=mod -modfile=.bingo/goreleaser.mod -o=$(GORELEASER) "github.com/goreleaser/goreleaser" + +# tagged-or-empty returns $(OPM_IMAGE_REPO):$(1) when HEAD is assigned a non-prerelease semver tag, +# otherwise the empty string. An empty string causes goreleaser to skip building +# the manifest image for a trunk commit when it is not a release commit. +# In other words, this function will return "" if the tag is not in vX.Y.Z format. +define tagged-or-empty +$(shell \ + echo $(OPM_VERSION) | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$$' \ + && git describe --tags --exact-match HEAD >/dev/null 2>&1 \ + && echo "$(OPM_IMAGE_REPO):$(1)" || echo "" ) +endef + diff --git a/OPM_VERSION b/OPM_VERSION deleted file mode 100644 index 456e5c4ad..000000000 --- a/OPM_VERSION +++ /dev/null @@ -1 +0,0 @@ -1.12.6 diff --git a/OWNERS b/OWNERS index 34ac7133d..67ce7f24c 100644 --- a/OWNERS +++ b/OWNERS @@ -1,21 +1,32 @@ # approval == this is a good idea /approve approvers: - - ecordell - - njhale + - awgreene - dinhxuanvu + - grokspawn + - joelanford - kevinrizza - - benluddy + - njhale + - oceanc80 + - perdasilva # review == this code is good /lgtm reviewers: - - ecordell - - njhale - - dinhxuanvu - - kevinrizza - - gallettilance - anik120 - - exdx + - ankitathomas - awgreene - - Bowenislandsong - benluddy + - dinhxuanvu + - everettraven + - exdx + - gallettilance + - grokspawn + - jmrodri + - joelanford + - kevinrizza + - njhale + - oceanc80 + - perdasilva + - rashmigottipati + - theishshah + - varshaprasad96 # Bugzilla component component: "OLM" diff --git a/README.md b/README.md index 263e88cc6..8e1ea563c 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,41 @@ -[](https://travis-ci.com/operator-framework/operator-registry) # operator-registry -Operator Registry runs in a Kubernetes or OpenShift cluster to provide operator catalog data to [Operator Lifecycle Manager](https://github.com/operator-framework/operator-lifecycle-manager). +Operator Registry runs in a Kubernetes or OpenShift cluster to provide operator catalog data to [Operator Lifecycle Manager](https://github.com/operator-framework/operator-lifecycle-manager). + +# Certificate of Origin + +By contributing to this project you agree to the Developer Certificate of +Origin (DCO). This document was created by the Linux Kernel community and is a +simple statement that you, as a contributor, have the legal right to make the +contribution. See the [DCO](DCO) file for details. # Overview This project provides the following binaries: * `opm`, which generates and updates registry databases as well as the index images that encapsulate them. - * `initializer`, which takes as an input a directory of operator manifests and outputs a sqlite database containing the same data for querying. + * `initializer`, which takes as an input a directory of operator manifests and outputs a sqlite database containing the same data for querying + * Deprecated - use `opm registry|index add` instead * `registry-server`, which takes a sqlite database loaded with manifests, and exposes a gRPC interface to it. + * Deprecated - use `opm registry serve` instead * `configmap-server`, which takes a kubeconfig and a configmap reference, and parses the configmap into the sqlite database before exposing it via the same interface as `registry-server`. - + And libraries: - - * `pkg/client` - providing a high-level client interface for the gRPC api. - * `pkg/api` - providing low-level client libraries for the gRPC interface exposed by `registry-server`. - * `pkg/registry` - providing basic registry types like Packages, Channels, and Bundles. - * `pkg/sqlite` - providing interfaces for building sqlite manifest databases from `ConfigMap`s or directories, and for querying an existing sqlite database. - * `pkg/lib` - providing external interfaces for interacting with this project as an api that defines a set of standards for operator bundles and indexes. - * `pkg/containertools` - providing an interface to interact with and shell out to common container tooling binaries (if installed on the environment) -# Manifest format +* `pkg/client` - providing a high-level client interface for the gRPC api. +* `pkg/api` - providing low-level client libraries for the gRPC interface exposed by `registry-server`. +* `pkg/registry` - providing basic registry types like Packages, Channels, and Bundles. +* `pkg/sqlite` - providing interfaces for building sqlite manifest databases from `ConfigMap`s or directories, and for querying an existing sqlite database. +* `pkg/lib` - providing external interfaces for interacting with this project as an api that defines a set of standards for operator bundles and indexes. +* `pkg/containertools` - providing an interface to interact with and shell out to common container tooling binaries (if installed on the environment) + +**NOTE:** The purpose of `opm` tool is to help who needs to manage index catalogues for OLM instances. However, if you are looking for a tool to help you to integrate your operator project with OLM then you should use [Operator-SDK](https://github.com/operator-framework/operator-sdk). +# Manifest format We refer to a directory of files with one ClusterServiceVersion as a "bundle". A bundle typically includes a ClusterServiceVersion and the CRDs that define the owned APIs of the CSV in its manifest directory, though additional objects may be included. It also includes an annotations file in its metadata folder which defines some higher level aggregate data that helps to describe the format and package information about how the bundle should be added into an index of bundles. -``` +```bash # example bundle etcd ├── manifests @@ -38,9 +47,9 @@ We refer to a directory of files with one ClusterServiceVersion as a "bundle". A When loading manifests into the database, the following invariants are validated: - * The bundle must have at least one channel defined in the annotations. - * Every bundle has exactly one ClusterServiceVersion. - * If a ClusterServiceVersion `owns` a CRD, that CRD must exist in the bundle. +* The bundle must have at least one channel defined in the annotations. +* Every bundle has exactly one ClusterServiceVersion. +* If a ClusterServiceVersion `owns` a CRD, that CRD must exist in the bundle. Bundle directories are identified solely by the fact that they contain a ClusterServiceVersion, which provides an amount of freedom for layout of manifests. @@ -50,7 +59,6 @@ Check out the [operator bundle design](docs/design/operator-bundle.md) for more Using [OCI spec](https://github.com/opencontainers/image-spec/blob/master/spec.md) container images as a method of storing the manifest and metadata contents of individual bundles, `opm` interacts directly with these images to generate and incrementally update the database. Once you have your [manifests defined](https://operator-framework.github.io/olm-book/docs/packaging-an-operator.html#writing-your-operator-manifests) and have created a directory in the format defined above, building the image is as simple as defining a [Dockerfile](docs/design/operator-bundle.md#Bundle-Dockerfile) and building that image: - ```sh podman build -t quay.io/my-container-registry-namespace/my-manifest-bundle:latest -f bundle.Dockerfile . ``` @@ -63,6 +71,8 @@ podman push quay.io/my-container-registry-namespace/my-manifest-bundle:latest Of course, this build step can be done with any other OCI spec container tools like `docker`, `buildah`, `libpod`, etc. +Note that you do not need to create your bundle manually. [Operator-SDK](https://github.com/operator-framework/operator-sdk) provide features and helpers to build, to update, to validate and to test bundles for projects which follows the SDK layout or not. For more information check its documentations over [Integration with OLM](https://sdk.operatorframework.io/docs/olm-integration) + # Building an index of Operators using `opm` Now that you have published the container image containing your manifests, how do you actually make that bundle available to other users' Kubernetes clusters so that the Operator Lifecycle Manager can install the operator? This is where the meat of the `operator-registry` project comes in. OLM has the concept of [CatalogSources](https://operator-framework.github.io/olm-book/docs/glossary.html#catalogsources) which define a reference to what packages are available to install onto a cluster. To make your bundle available, you can add the bundle to a container image which the CatalogSource points to. This image contains a database of pointers to bundle images that OLM can pull and extract the manifests from in order to install an operator. So, to make your operator available to OLM, you can generate an index image via opm with your bundle reference included: @@ -134,7 +144,7 @@ apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: etcd-subscription - namespace: default + namespace: default spec: channel: alpha name: etcd @@ -144,7 +154,13 @@ spec: # Using the catalog locally -[grpcurl](https://github.com/fullstorydev/grpcurl) is a useful tool for interacting with the example catalog server. +After starting a catalog locally: + +```sh +docker run --rm -p 50051:50051 <index image> +``` + +[grpcurl](https://github.com/fullstorydev/grpcurl) is a useful tool for interacting with the api: ```sh $ grpcurl -plaintext localhost:50051 list api.Registry @@ -160,8 +176,9 @@ ListPackages ``` ```sh -$ grpcurl -plaintext localhost:50051 api.Registry/ListPackages +grpcurl -plaintext localhost:50051 api.Registry/ListPackages ``` + ```json { "name": "etcd" @@ -172,8 +189,9 @@ $ grpcurl -plaintext localhost:50051 api.Registry/ListPackages ``` ```sh -$ grpcurl -plaintext -d '{"name":"etcd"}' localhost:50051 api.Registry/GetPackage +grpcurl -plaintext -d '{"name":"etcd"}' localhost:50051 api.Registry/GetPackage ``` + ```json { "name": "etcd", @@ -191,6 +209,7 @@ $ grpcurl -plaintext -d '{"name":"etcd"}' localhost:50051 api.Registry/GetPackag $ grpcurl localhost:50051 describe api.Registry.GetBundleForChannel api.Registry.GetBundleForChannel is a method: ``` + ```json { "name": "GetBundleForChannel", @@ -205,6 +224,7 @@ api.Registry.GetBundleForChannel is a method: $ grpcurl localhost:50051 describe api.GetBundleInChannelRequest api.GetBundleInChannelRequest is a message: ``` + ```json { "name": "GetBundleInChannelRequest", @@ -237,16 +257,17 @@ api.GetBundleInChannelRequest is a message: ``` ```sh -$ grpcurl -plaintext -d '{"pkgName":"etcd","channelName":"alpha"}' localhost:50051 api.Registry/GetBundleForChannel +grpcurl -plaintext -d '{"pkgName":"etcd","channelName":"alpha"}' localhost:50051 api.Registry/GetBundleForChannel ``` + ```json { "csvName": "etcdoperator.v0.9.2", - "csvJson": "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"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\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}", + "csvJson": "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"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\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}", "object": [ "{\"apiVersion\":\"apiextensions.k8s.io/v1beta1\",\"kind\":\"CustomResourceDefinition\",\"metadata\":{\"name\":\"etcdbackups.etcd.database.coreos.com\"},\"spec\":{\"group\":\"etcd.database.coreos.com\",\"names\":{\"kind\":\"EtcdBackup\",\"listKind\":\"EtcdBackupList\",\"plural\":\"etcdbackups\",\"singular\":\"etcdbackup\"},\"scope\":\"Namespaced\",\"version\":\"v1beta2\"}}", "{\"apiVersion\":\"apiextensions.k8s.io/v1beta1\",\"kind\":\"CustomResourceDefinition\",\"metadata\":{\"name\":\"etcdclusters.etcd.database.coreos.com\"},\"spec\":{\"group\":\"etcd.database.coreos.com\",\"names\":{\"kind\":\"EtcdCluster\",\"listKind\":\"EtcdClusterList\",\"plural\":\"etcdclusters\",\"shortNames\":[\"etcdclus\",\"etcd\"],\"singular\":\"etcdcluster\"},\"scope\":\"Namespaced\",\"version\":\"v1beta2\"}}", - "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"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\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}", + "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"iVBORw0KGgoAAAANSUhEUgAAAOEAAADZCAYAAADWmle6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAEKlJREFUeNrsndt1GzkShmEev4sTgeiHfRYdgVqbgOgITEVgOgLTEQydwIiKwFQCayoCU6+7DyYjsBiBFyVVz7RkXvqCSxXw/+f04XjGQ6IL+FBVuL769euXgZ7r39f/G9iP0X+u/jWDNZzZdGI/Ftama1jjuV4BwmcNpbAf1Fgu+V/9YRvNAyzT2a59+/GT/3hnn5m16wKWedJrmOCxkYztx9Q+py/+E0GJxtJdReWfz+mxNt+QzS2Mc0AI+HbBBwj9QViKbH5t64DsP2fvmGXUkWU4WgO+Uve2YQzBUGd7r+zH2ZG/tiUQc4QxKwgbwFfVGwwmdLL5wH78aPC/ZBem9jJpCAX3xtcNASSNgJLzUPSQyjB1zQNl8IQJ9MIU4lx2+Jo72ysXYKl1HSzN02BMa/vbZ5xyNJIshJzwf3L0dQhJw4Sih/SFw9Tk8sVeghVPoefaIYCkMZCKbrcP9lnZuk0uPUjGE/KE8JQry7W2tgfuC3vXgvNV+qSQbyFtAtyWk7zWiYevvuUQ9QEQCvJ+5mmu6dTjz1zFHLFj8Eb87MtxaZh/IQFIHom+9vgTWwZxAQjT9X4vtbEVPojwjiV471s00mhAckpwGuCn1HtFtRDaSh6y9zsL+LNBvCG/24ThcxHObdlWc1v+VQJe8LcO0jwtuF8BwnAAUgP9M8JPU2Me+Oh12auPGT6fHuTePE3bLDy+x9pTLnhMn+07TQGh//Bz1iI0c6kvtqInjvPZcYR3KsPVmUsPYt9nFig9SCY8VQNhpPBzn952bbgcsk2EvM89wzh3UEffBbyPqvBUBYQ8ODGPFOLsa7RF096WJ69L+E4EmnpjWu5o4ChlKaRTKT39RMMaVPEQRsz/nIWlDN80chjdJlSd1l0pJCAMVZsniobQVuxceMM9OFoaMd9zqZtjMEYYDW38Drb8Y0DYPLShxn0pvIFuOSxd7YCPet9zk452wsh54FJoeN05hcgSQoG5RR0Qh9Q4E4VvL4wcZq8UACgaRFEQKgSwWrkr5WFnGxiHSutqJGlXjBgIOayhwYBTA0ER0oisIVSUV0AAMT0IASCUO4hRIQSAEECMCCEPwqyQA0JCQBzEGjWNAqHiUVAoXUWbvggOIQCEAOJzxTjoaQ4AIaE64/aZridUsBYUgkhB15oGg1DBIl8IqirYwV6hPSGBSFteMCUBSVXwfYixBmamRubeMyjzMJQBDDowE3OesDD+zwqFoDqiEwXoXJpljB+PvWJGy75BKF1FPxhKygJuqUdYQGlLxNEXkrYyjQ0GbaAwEnUIlLRNvVjQDYUAsJB0HKLE4y0AIpQNgCIhBIhQTgCKhZBBpAN/v6LtQI50JfUgYOnnjmLUFHKhjxbAmdTCaTiBm3ovLPqG2urWAij6im0Nd9aTN9ygLUEt9LgSRnohxUPIKxlGaE+/6Y7znFf0yX+GnkvFFWmarkab2o9PmTeq8sbd2a7DaysXz7i64VeznN4jCQhN9gdDbRiuWrfrsq0mHIrlaq+hlotCtd3Um9u0BYWY8y5D67wccJoZjFca7iUs9VqZcfsZwTd1sbWGG+OcYaTnPAP7rTQVVlM4Sg3oGvB1tmNh0t/HKXZ1jFoIMwCQjtqbhNxUmkGYqgZEDZP11HN/S3gAYRozf0l8C5kKEKUvW0t1IfeWG/5MwgheZTT1E0AEhDkAePQO+Ig2H3DncAkQM4cwUQCD530dU4B5Yvmi2LlDqXfWrxMCcMth51RToRMNUXFnfc2KJ0+Ryl0VNOUwlhh6NoxK5gnViTgQpUG4SqSyt5z3zRJpuKmt3Q1614QaCBPaN6je+2XiFcWAKOXcUfIYKRyL/1lb7pe5VxSxxjQ6hImshqGRt5GWZVKO6q2wHwujfwDtIvaIdexj8Cm8+a68EqMfox6x/voMouZF4dHnEGNeCDMwT6vdNfekH1MafMk4PI06YtqLVGl95aEM9Z5vAeCTOA++YLtoVJRrsqNCaJ6WRmkdYaNec5BT/lcTRMqrhmwfjbpkj55+OKp8IEbU/JLgPJE6Wa3TTe9sHS+ShVD5QIyqIxMEwKh12olC6mHIed5ewEop80CNlfIOADYOT2nd6ZXCop+Ebqchc0JqxKcKASxChycJgUh1rnHA5ow9eTrhqNI7JWiAYYwBGGdpyNLoGw0Pkh96h1BpHihyywtATDM/7Hk2fN9EnH8BgKJCU4ooBkbXFMZJiPbrOyecGl3zgQDQL4hk10IZiOe+5w99Q/gBAEIJgPhJM4QAEEoFREAIAAEiIASAkD8Qt4AQAEIAERAGFlX4CACKAXGVM4ivMwWwCLFAlyeoaa70QePKm5Dlp+/n+ye/5dYgva6YsUaVeMa+tzNFeJtWwc+udbJ0Fg399kLielQJ5Ze61c2+7ytA6EZetiPxZC6tj22yJCv6jUwOyj/zcbqAxOMyAKEbfeHtNa7DtYXptjsk2kJxR+eIeim/tHNofUKYy8DMrQcAKWz6brpvzyIAlpwPhQ49l6b7skJf5Z+YTOYQc4FwLDxvoTDwaygQK+U/kVr+ytSFBG01Q3gnJJR4cNiAhx4HDub8/b5DULXlj6SVZghFiE+LdvE9vo/o8Lp1RmH5hzm0T6wdbZ6n+D6i44zDRc3ln6CpAEJfXiRU45oqLz8gFAThWsh7ughrRibc0QynHgZpNJa/ENJ+loCwu/qOGnFIjYR/n7TfgycULhcQhu6VC+HfF+L3BoAQ4WiZTw1M+FPCnA2gKC6/FAhXgDC+ojQGh3NuWsvfF1L/D5ohlCKtl1j2ldu9a/nPAKFwN56Bst10zCG0CPleXN/zXPgHQZXaZaBgrbzyY5V/mUA+6F0hwtGN9rwu5DVZPuwWqfxdFz1LWbJ2lwKEa+0Qsm4Dl3fp+Pu0lV97PgwIPfSsS+UQhj5Oo+vvFULazRIQyvGEcxPuNLCth2MvFsrKn8UOilAQShkh7TTczYNMoS6OdP47msrPi82lXKGWhCdMZYS0bFy+vcnGAjP1CIfvgbKNA9glecEH9RD6Ol4wRuWyN/G9MHnksS6o/GPf5XcwNSUlHzQhDuAKtWJmkwKElU7lylP5rgIcsquh/FI8YZCDpkJBuE4FQm7Icw8N+SrUGaQKyi8FwiDt1ve5o+Vu7qYHy/psgK8cvh+FTYuO77bhEC7GuaPiys/L1X4IgXDL+e3M5+ovLxBy5VLuIebw1oqcHoPfoaMJUsHays878r8KbDc3xtPx/84gZPBG/JwaufrsY/SRG/OY3//8QMNdsvdZCFtbW6f8pFuf5bflILAlX7O+4fdfugKyFYS8T2zAsXthdG0VurPGKwI06oF5vkBgHWkNp6ry29+lsPZMU3vijnXFNmoclr+6+Ou/FIb8yb30sS8YGjmTqCLyQsi5N/6ZwKs0Yenj68pfPjF6N782Dp2FzV9CTyoSeY8mLK16qGxIkLI8oa1n8tz9juP40DlK0epxYEbojbq+9QfurBeVIlCO9D2396bxiV4lkYQ3hOAFw2pbhqMGISkkQOMcQ9EqhDmGZZdo92JC0YHRNTfoSg+5e0IT+opqCKHoIU+4ztQIgBD1EFNrQAgIpYSil9lDmPHqkROPt+JC6AgPquSuumJmg0YARVCuneDfvPVeJokZ6pIXDkNxQtGzTF9/BQjRG0tQznfb74RwCQghpALBtIQnfK4zhxdyQvVCUeknMIT3hLyY+T5jo0yABqKPQNpUNw/09tGZod5jgCaYFxyYvJcNPkv9eof+I3pnCFEHIETjSM8L9tHZHYCQT9PaZGycU6yg8S4akDnJ+P03L0+t23XGzCLzRgII/Wqa+fv/xlfvmKvMUOcOrlCDdoei1MGdZm6G5VEIfRzzjd4aQs69n699Rx7ewhvCGzr2gmTPs8zNsJOrXt24FbkhhOjCfT4ICA/rPbyhUy94Dks0gJCX1NzCZui9YUd3oei+c257TalFbgg19ILHrlrL2gvWgXAL26EX76gZTNASQnad8Ibwhl284NhgXpB0c+jKhWO3Ms1hP9ihJYB9eMF6qd1BCPk0qA1s+LimFIu7m4nsdQIzPK4VbQ8hYvrnuSH2G9b2ggP78QmWqBdF9Vx8SSY6QYdUW7BTA1schZATyhvY8lHvcRbNUS9YGFy2U+qmzh2YPVc0I7yAOFyHfRpyUwtCSzOdPXMHmz7qDIM0e0V2wZTEk+6Ym6N63eBLp/b5Bts+2cKCSJ/LuoZO3ANSiE5hKAZjnvNSS4931jcw9jpwT0feV/qSJ1pVtCyfHKDkvK8Ejx7pUxGh2xFNSwx8QTi2H9ceC0/nni64MS/5N5dG39pDqvRV+WgGk71c9VFXF9b+xYvOw/d61iv7m3MvEHryhvecwC52jSSx4VIIgwnMNT/UsTxIgpPt3K/ARj15CptwL3Zd/ceDSATj2DGQjbxgWwhdeMMte7zpy5On9vymRm/YxBYljGVjKWF9VJf7I1+sex3wY8w/V1QPTborW/72gkdsRDaZMJBdbdHIC7aCkAu9atlLbtnrzerMnyToDaGwelOnk3/hHSem/ZK7e/t7jeeR20LYBgqa8J80gS8jbwi5F02Uj1u2NYJxap8PLkJfLxA2hIJyvnHX/AfeEPLpBfe0uSFHbnXaea3Qd5d6HcpYZ8L6M7lnFwMQ3MNg+RxUR1+6AshtbsVgfXTEg1sIGax9UND2p7f270wdG3eK9gXVGHdw2k5sOyZv+Nbs39Z308XR9DqWb2J+PwKDhuKHPobfuXf7gnYGHdCs7bhDDadD4entDug7LWNsnRNW4mYqwJ9dk+GGSTPBiA2j0G8RWNM5upZtcG4/3vMfP7KnbK2egx6CCnDPhRn7NgD3cghLIad5WcM2SO38iqHvvMOosyeMpQ5zlVCaaj06GVs9xUbHdiKoqrHWgquFEFMWUEWfXUxJAML23hAHFOctmjZQffKD2pywkhtSGHKNtpitLroscAeE7kCkSsC60vxEl6yMtL9EL5HKGCMszU5bk8gdkklAyEn5FO0yK419rIxBOIqwFMooDE0tHEVYijAUECIshRCGIhxFWIowFJ5QkEYIS5PTJrUwNGlPyN6QQPyKtpuM1E/K5+YJDV/MiA3AaehzqgAm7QnZG9IGYKo8bHnSK7VblLL3hOwNHziPuEGOqE5brrdR6i+atCfckyeWD47HkAkepRGLY/e8A8J0gCwYSNypF08bBm+e6zVz2UL4AshhBUjML/rXLefqC82bcQFhGC9JDwZ1uuu+At0S5gCETYHsV4DUeD9fDN2Zfy5OXaW2zAwQygCzBLJ8cvaW5OXKC1FxfTggFAHmoAJnSiOw2wps9KwRWgJCLaEswaj5NqkLwAYIU4BxqTSXbHXpJdRMPZgAOiAMqABCNGYIEEJutEK5IUAIwYMDQgiCACEEAcJs1Vda7gGqDhCmoiEghAAhBAHCrKXVo2C1DCBMRlp37uMIEECoX7xrX3P5C9QiINSuIcoPAUI0YkAICLNWgfJDh4T9hH7zqYH9+JHAq7zBqWjwhPAicTVCVQJCNF50JghHocahKK0X/ZnQKyEkhSdUpzG8OgQI42qC94EQjsYLRSmH+pbgq73L6bYkeEJ4DYTYmeg1TOBFc/usTTp3V9DdEuXJ2xDCUbXhaXk0/kAYmBvuMB4qkC35E5e5AMKkwSQgyxufyuPy6fMMgAFCSI73LFXU/N8AmEL9X4ABACNSKMHAgb34AAAAAElFTkSuQmCC\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}", "{\"apiVersion\":\"apiextensions.k8s.io/v1beta1\",\"kind\":\"CustomResourceDefinition\",\"metadata\":{\"name\":\"etcdrestores.etcd.database.coreos.com\"},\"spec\":{\"group\":\"etcd.database.coreos.com\",\"names\":{\"kind\":\"EtcdRestore\",\"listKind\":\"EtcdRestoreList\",\"plural\":\"etcdrestores\",\"singular\":\"etcdrestore\"},\"scope\":\"Namespaced\",\"version\":\"v1beta2\"}}" ] } diff --git a/alpha/action/generate_dockerfile.go b/alpha/action/generate_dockerfile.go new file mode 100644 index 000000000..fc3a8ff1e --- /dev/null +++ b/alpha/action/generate_dockerfile.go @@ -0,0 +1,82 @@ +package action + +import ( + "fmt" + "io" + "text/template" + + "github.com/operator-framework/operator-registry/pkg/containertools" +) + +type GenerateDockerfile struct { + BaseImage string + BuilderImage string + IndexDir string + ExtraLabels map[string]string + Writer io.Writer +} + +func (i GenerateDockerfile) Run() error { + if err := i.validate(); err != nil { + return err + } + + t, err := template.New("dockerfile").Parse(dockerfileTmpl) + if err != nil { + // The template is hardcoded in the binary, so if + // there is a parse error, it was a programmer error. + panic(err) + } + return t.Execute(i.Writer, i) +} + +func (i GenerateDockerfile) validate() error { + if i.BaseImage == "" { + return fmt.Errorf("base image is unset") + } + if i.IndexDir == "" { + return fmt.Errorf("index directory is unset") + } + return nil +} + +const dockerfileTmpl = `# The builder image is expected to contain +# /bin/opm (with serve subcommand) +FROM {{.BuilderImage}} as builder + +# Copy FBC root into image at /configs and pre-populate serve cache +ADD {{.IndexDir}} /configs +RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] + +FROM {{.BaseImage}} + +{{- if ne .BaseImage "scratch" }} +# The base image is expected to contain +# /bin/opm (with serve subcommand) and /bin/grpc_health_probe + +# Configure the entrypoint and command +ENTRYPOINT ["/bin/opm"] +CMD ["serve", "/configs", "--cache-dir=/tmp/cache"] +{{- else }} +# OLMv0 CatalogSources that use binary-less images must set: +# spec: +# grpcPodConfig: +# extractContent: +# catalogDir: /configs +# cacheDir: /tmp/cache +{{- end }} + +COPY --from=builder /configs /configs +COPY --from=builder /tmp/cache /tmp/cache + +# Set FBC-specific label for the location of the FBC root directory +# in the image +LABEL ` + containertools.ConfigsLocationLabel + `=/configs +{{- if .ExtraLabels }} + +# Set other custom labels +{{- range $key, $value := .ExtraLabels }} +LABEL "{{ $key }}"="{{ $value }}" +{{- end }} +{{- end }} +` diff --git a/alpha/action/generate_dockerfile_test.go b/alpha/action/generate_dockerfile_test.go new file mode 100644 index 000000000..0f94aa345 --- /dev/null +++ b/alpha/action/generate_dockerfile_test.go @@ -0,0 +1,221 @@ +package action + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGenerateDockerfile(t *testing.T) { + type spec struct { + name string + gen GenerateDockerfile + expectedDockerfile string + expectedErr string + } + + specs := []spec{ + { + name: "Fail/EmptyBaseImage", + gen: GenerateDockerfile{ + IndexDir: "bar", + ExtraLabels: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + expectedErr: "base image is unset", + }, + { + name: "Fail/EmptyFromDir", + gen: GenerateDockerfile{ + BaseImage: "foo", + ExtraLabels: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + expectedErr: "index directory is unset", + }, + { + name: "Success/WithoutExtraLabels", + gen: GenerateDockerfile{ + BuilderImage: "foo", + BaseImage: "foo", + IndexDir: "bar", + }, + expectedDockerfile: `# The builder image is expected to contain +# /bin/opm (with serve subcommand) +FROM foo as builder + +# Copy FBC root into image at /configs and pre-populate serve cache +ADD bar /configs +RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] + +FROM foo +# The base image is expected to contain +# /bin/opm (with serve subcommand) and /bin/grpc_health_probe + +# Configure the entrypoint and command +ENTRYPOINT ["/bin/opm"] +CMD ["serve", "/configs", "--cache-dir=/tmp/cache"] + +COPY --from=builder /configs /configs +COPY --from=builder /tmp/cache /tmp/cache + +# Set FBC-specific label for the location of the FBC root directory +# in the image +LABEL operators.operatorframework.io.index.configs.v1=/configs +`, + }, + { + name: "Success/WithExtraLabels", + gen: GenerateDockerfile{ + BuilderImage: "foo", + BaseImage: "foo", + IndexDir: "bar", + ExtraLabels: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + expectedDockerfile: `# The builder image is expected to contain +# /bin/opm (with serve subcommand) +FROM foo as builder + +# Copy FBC root into image at /configs and pre-populate serve cache +ADD bar /configs +RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] + +FROM foo +# The base image is expected to contain +# /bin/opm (with serve subcommand) and /bin/grpc_health_probe + +# Configure the entrypoint and command +ENTRYPOINT ["/bin/opm"] +CMD ["serve", "/configs", "--cache-dir=/tmp/cache"] + +COPY --from=builder /configs /configs +COPY --from=builder /tmp/cache /tmp/cache + +# Set FBC-specific label for the location of the FBC root directory +# in the image +LABEL operators.operatorframework.io.index.configs.v1=/configs + +# Set other custom labels +LABEL "key1"="value1" +LABEL "key2"="value2" +`, + }, + + { + name: "Scratch/Fail/EmptyBaseImage", + gen: GenerateDockerfile{ + BuilderImage: "foo", + IndexDir: "bar", + ExtraLabels: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + expectedErr: "base image is unset", + }, + { + name: "Scratch/Fail/EmptyFromDir", + gen: GenerateDockerfile{ + BuilderImage: "foo", + BaseImage: "scratch", + ExtraLabels: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + expectedErr: "index directory is unset", + }, + { + name: "Scratch/Success/WithoutExtraLabels", + gen: GenerateDockerfile{ + BuilderImage: "foo", + BaseImage: "scratch", + IndexDir: "bar", + }, + expectedDockerfile: `# The builder image is expected to contain +# /bin/opm (with serve subcommand) +FROM foo as builder + +# Copy FBC root into image at /configs and pre-populate serve cache +ADD bar /configs +RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] + +FROM scratch +# OLMv0 CatalogSources that use binary-less images must set: +# spec: +# grpcPodConfig: +# extractContent: +# catalogDir: /configs +# cacheDir: /tmp/cache + +COPY --from=builder /configs /configs +COPY --from=builder /tmp/cache /tmp/cache + +# Set FBC-specific label for the location of the FBC root directory +# in the image +LABEL operators.operatorframework.io.index.configs.v1=/configs +`, + }, + { + name: "Scratch/Success/WithExtraLabels", + gen: GenerateDockerfile{ + BuilderImage: "foo", + BaseImage: "scratch", + IndexDir: "bar", + ExtraLabels: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + expectedDockerfile: `# The builder image is expected to contain +# /bin/opm (with serve subcommand) +FROM foo as builder + +# Copy FBC root into image at /configs and pre-populate serve cache +ADD bar /configs +RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"] + +FROM scratch +# OLMv0 CatalogSources that use binary-less images must set: +# spec: +# grpcPodConfig: +# extractContent: +# catalogDir: /configs +# cacheDir: /tmp/cache + +COPY --from=builder /configs /configs +COPY --from=builder /tmp/cache /tmp/cache + +# Set FBC-specific label for the location of the FBC root directory +# in the image +LABEL operators.operatorframework.io.index.configs.v1=/configs + +# Set other custom labels +LABEL "key1"="value1" +LABEL "key2"="value2" +`, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + buf := bytes.Buffer{} + s.gen.Writer = &buf + err := s.gen.Run() + if s.expectedErr != "" { + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) + require.Equal(t, s.expectedDockerfile, buf.String()) + } + }) + } +} diff --git a/alpha/action/init.go b/alpha/action/init.go new file mode 100644 index 000000000..242d8f818 --- /dev/null +++ b/alpha/action/init.go @@ -0,0 +1,52 @@ +package action + +import ( + "fmt" + "io" + + "github.com/h2non/filetype" + + "github.com/operator-framework/operator-registry/alpha/declcfg" +) + +type Init struct { + Package string + DefaultChannel string + DescriptionReader io.Reader + IconReader io.Reader +} + +func (i Init) Run() (*declcfg.Package, error) { + pkg := &declcfg.Package{ + // TODO(joelanford): Use a constant for "olm.package" + Schema: "olm.package", + Name: i.Package, + DefaultChannel: i.DefaultChannel, + } + if i.DescriptionReader != nil { + descriptionData, err := io.ReadAll(i.DescriptionReader) + if err != nil { + return nil, fmt.Errorf("read description: %v", err) + } + pkg.Description = string(descriptionData) + } + + if i.IconReader != nil { + iconData, err := io.ReadAll(i.IconReader) + if err != nil { + return nil, fmt.Errorf("read icon: %v", err) + } + iconType, err := filetype.Match(iconData) + if err != nil { + return nil, fmt.Errorf("detect icon mediatype: %v", err) + } + if iconType.MIME.Type != "image" { + return nil, fmt.Errorf("detected invalid type %q: not an image", iconType.MIME.Value) + } + pkg.Icon = &declcfg.Icon{ + Data: iconData, + MediaType: iconType.MIME.Value, + } + } + return pkg, nil +} diff --git a/alpha/action/init_test.go b/alpha/action/init_test.go new file mode 100644 index 000000000..3825571d5 --- /dev/null +++ b/alpha/action/init_test.go @@ -0,0 +1,139 @@ +package action_test + +import ( + "bytes" + "errors" + "testing" + "testing/iotest" + + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/action" + "github.com/operator-framework/operator-registry/alpha/declcfg" +) + +const ( + svgIcon = `<svg viewBox="0 0 100 100"><circle cx="25" cy="25" r="25"/></svg>` +) + +func TestInit(t *testing.T) { + type spec struct { + name string + init action.Init + expectPkg *declcfg.Package + assertion require.ErrorAssertionFunc + } + + specs := []spec{ + { + name: "Success/Empty", + init: action.Init{}, + expectPkg: &declcfg.Package{ + Schema: "olm.package", + }, + assertion: require.NoError, + }, + { + name: "Success/SetPackage", + init: action.Init{ + Package: "foo", + }, + expectPkg: &declcfg.Package{ + Schema: "olm.package", + Name: "foo", + }, + assertion: require.NoError, + }, + { + name: "Success/SetDefaultChannel", + init: action.Init{ + DefaultChannel: "foo", + }, + expectPkg: &declcfg.Package{ + Schema: "olm.package", + DefaultChannel: "foo", + }, + assertion: require.NoError, + }, + { + name: "Success/SetDescription", + init: action.Init{ + DescriptionReader: bytes.NewBufferString("foo"), + }, + expectPkg: &declcfg.Package{ + Schema: "olm.package", + Description: "foo", + }, + assertion: require.NoError, + }, + { + name: "Success/SetIcon", + init: action.Init{ + IconReader: bytes.NewBufferString(svgIcon), + }, + expectPkg: &declcfg.Package{ + Schema: "olm.package", + Icon: &declcfg.Icon{ + Data: bytes.NewBufferString(svgIcon).Bytes(), + MediaType: "image/svg+xml", + }, + }, + assertion: require.NoError, + }, + { + name: "Success/SetAll", + init: action.Init{ + Package: "a", + DefaultChannel: "b", + DescriptionReader: bytes.NewBufferString("c"), + IconReader: bytes.NewBufferString(svgIcon), + }, + expectPkg: &declcfg.Package{ + Schema: "olm.package", + Name: "a", + DefaultChannel: "b", + Description: "c", + Icon: &declcfg.Icon{ + Data: bytes.NewBufferString(svgIcon).Bytes(), + MediaType: "image/svg+xml", + }, + }, + assertion: require.NoError, + }, + { + name: "Fail/ReadDescription", + init: action.Init{ + DescriptionReader: iotest.ErrReader(errors.New("fail")), + }, + assertion: require.Error, + }, + { + name: "Fail/ReadIcon", + init: action.Init{ + IconReader: iotest.ErrReader(errors.New("fail")), + }, + assertion: require.Error, + }, + { + name: "Fail/IconNotImage", + init: action.Init{ + IconReader: bytes.NewBufferString("foo"), + }, + assertion: require.Error, + }, + { + name: "Fail/EmptyIcon", + init: action.Init{ + IconReader: bytes.NewBuffer(nil), + }, + assertion: require.Error, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + actualPkg, actualErr := s.init.Run() + s.assertion(t, actualErr) + require.Equal(t, s.expectPkg, actualPkg) + }) + } +} diff --git a/alpha/action/list.go b/alpha/action/list.go new file mode 100644 index 000000000..80c014d1d --- /dev/null +++ b/alpha/action/list.go @@ -0,0 +1,212 @@ +package action + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "sort" + "strings" + "text/tabwriter" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/pkg/image" +) + +type ListPackages struct { + IndexReference string + Registry image.Registry +} + +func (l *ListPackages) Run(ctx context.Context) (*ListPackagesResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference, l.Registry) + if err != nil { + return nil, err + } + + pkgs := []model.Package{} + for _, pkg := range m { + pkgs = append(pkgs, *pkg) + } + sort.Slice(pkgs, func(i, j int) bool { + return pkgs[i].Name < pkgs[j].Name + }) + return &ListPackagesResult{Packages: pkgs}, nil +} + +type ListPackagesResult struct { + Packages []model.Package +} + +func (r *ListPackagesResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "NAME\tDISPLAY NAME\tDEFAULT CHANNEL"); err != nil { + return err + } + for _, pkg := range r.Packages { + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\n", pkg.Name, getDisplayName(pkg), pkg.DefaultChannel.Name); err != nil { + return err + } + } + return tw.Flush() +} + +func getDisplayName(pkg model.Package) string { + if pkg.DefaultChannel == nil { + return "" + } + head, err := pkg.DefaultChannel.Head() + if err != nil || head == nil || head.CsvJSON == "" { + return "" + } + + csv := v1alpha1.ClusterServiceVersion{} + if err := json.Unmarshal([]byte(head.CsvJSON), &csv); err != nil { + return "" + } + return csv.Spec.DisplayName +} + +type ListChannels struct { + IndexReference string + PackageName string + Registry image.Registry +} + +func (l *ListChannels) Run(ctx context.Context) (*ListChannelsResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference, l.Registry) + if err != nil { + return nil, err + } + + pkgs, err := getPackages(m, l.PackageName) + if err != nil { + return nil, err + } + + channels := []model.Channel{} + for _, pkg := range pkgs { + for _, ch := range pkg.Channels { + channels = append(channels, *ch) + } + } + + sort.Slice(channels, func(i, j int) bool { + if channels[i].Package.Name != channels[j].Package.Name { + return channels[i].Package.Name < channels[j].Package.Name + } + return channels[i].Name < channels[j].Name + }) + return &ListChannelsResult{Channels: channels}, nil +} + +type ListChannelsResult struct { + Channels []model.Channel +} + +func (r *ListChannelsResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "PACKAGE\tCHANNEL\tHEAD"); err != nil { + return err + } + for _, ch := range r.Channels { + headStr := "" + head, err := ch.Head() + if err != nil { + headStr = fmt.Sprintf("ERROR: %s", err) + } else { + headStr = head.Name + } + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\n", ch.Package.Name, ch.Name, headStr); err != nil { + return err + } + } + return tw.Flush() +} + +type ListBundles struct { + IndexReference string + PackageName string + Registry image.Registry +} + +func (l *ListBundles) Run(ctx context.Context) (*ListBundlesResult, error) { + m, err := indexRefToModel(ctx, l.IndexReference, l.Registry) + if err != nil { + return nil, err + } + + pkgs, err := getPackages(m, l.PackageName) + if err != nil { + return nil, err + } + + bundles := []model.Bundle{} + for _, pkg := range pkgs { + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + bundles = append(bundles, *b) + } + } + } + + sort.Slice(bundles, func(i, j int) bool { + if bundles[i].Package.Name != bundles[j].Package.Name { + return bundles[i].Package.Name < bundles[j].Package.Name + } + if bundles[i].Channel.Name != bundles[j].Channel.Name { + return bundles[i].Channel.Name < bundles[j].Channel.Name + } + return bundles[i].Name < bundles[j].Name + }) + return &ListBundlesResult{Bundles: bundles}, nil +} + +type ListBundlesResult struct { + Bundles []model.Bundle +} + +func (r *ListBundlesResult) WriteColumns(w io.Writer) error { + tw := tabwriter.NewWriter(w, 0, 4, 2, ' ', 0) + if _, err := fmt.Fprintln(tw, "PACKAGE\tCHANNEL\tBUNDLE\tREPLACES\tSKIPS\tSKIP RANGE\tIMAGE"); err != nil { + return err + } + for _, b := range r.Bundles { + if _, err := fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", b.Package.Name, b.Channel.Name, b.Name, b.Replaces, strings.Join(b.Skips, ","), b.SkipRange, b.Image); err != nil { + return err + } + } + return tw.Flush() +} + +func indexRefToModel(ctx context.Context, ref string, reg image.Registry) (model.Model, error) { + render := Render{ + Refs: []string{ref}, + AllowedRefMask: RefDCImage | RefDCDir | RefSqliteImage | RefSqliteFile, + Registry: reg, + } + cfg, err := render.Run(ctx) + if err != nil { + if errors.Is(err, ErrNotAllowed) { + return nil, fmt.Errorf("cannot list non-index %q", ref) + } + return nil, err + } + + return declcfg.ConvertToModel(*cfg) +} + +func getPackages(m model.Model, packageName string) (model.Model, error) { + if packageName == "" { + return m, nil + } + pkg, ok := m[packageName] + if !ok { + return nil, fmt.Errorf("package %q not found", packageName) + } + return model.Model{packageName: pkg}, nil +} diff --git a/alpha/action/list_test.go b/alpha/action/list_test.go new file mode 100644 index 000000000..090439d44 --- /dev/null +++ b/alpha/action/list_test.go @@ -0,0 +1,166 @@ +package action + +import ( + "bytes" + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestListPackages(t *testing.T) { + type spec struct { + name string + list ListPackages + expectedOut string + expectedErr string + } + + specs := []spec{ + { + name: "Success/ValidIndex", + list: ListPackages{IndexReference: "testdata/list-index"}, + expectedOut: `NAME DISPLAY NAME DEFAULT CHANNEL +bar Bar Operator beta +foo Foo Operator beta +`, + }, + { + name: "Error/UnknownIndex", + list: ListPackages{IndexReference: "unknown-index"}, + expectedErr: `render reference "unknown-index": failed to pull image "unknown-index": repository name must be canonical`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + res, err := s.list.Run(context.Background()) + if s.expectedErr != "" { + require.Nil(t, res) + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) + + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) + + require.Equal(t, s.expectedOut, buf.String()) + } + }) + } +} + +func TestListChannels(t *testing.T) { + type spec struct { + name string + list ListChannels + expectedOut string + expectedErr string + } + specs := []spec{ + { + name: "Success/WithPackage", + list: ListChannels{IndexReference: "testdata/list-index", PackageName: "foo"}, + expectedOut: `PACKAGE CHANNEL HEAD +foo beta foo.v0.2.0 +foo stable foo.v0.2.0 +`, + }, + { + name: "Success/WithoutPackage", + list: ListChannels{IndexReference: "testdata/list-index"}, + expectedOut: `PACKAGE CHANNEL HEAD +bar beta bar.v0.2.0 +bar stable bar.v0.2.0 +foo beta foo.v0.2.0 +foo stable foo.v0.2.0 +`, + }, + { + name: "Error/UnknownIndex", + list: ListChannels{IndexReference: "unknown-index"}, + expectedErr: `render reference "unknown-index": failed to pull image "unknown-index": repository name must be canonical`, + }, + { + name: "Error/UnknownPackage", + list: ListChannels{IndexReference: "testdata/list-index", PackageName: "unknown"}, + expectedErr: `package "unknown" not found`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + res, err := s.list.Run(context.Background()) + if s.expectedErr != "" { + require.Nil(t, res) + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) + + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) + + require.Equal(t, s.expectedOut, buf.String()) + } + }) + } +} + +func TestListBundles(t *testing.T) { + type spec struct { + name string + list ListBundles + expectedOut string + expectedErr string + } + specs := []spec{ + { + name: "Success/WithPackage", + list: ListBundles{IndexReference: "testdata/list-index", PackageName: "foo"}, + expectedOut: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE +foo beta foo.v0.1.0 <0.1.0 test.registry/foo-operator/foo-bundle:v0.1.0 +foo beta foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +`, + }, + { + name: "Success/WithoutPackage", + list: ListBundles{IndexReference: "testdata/list-index"}, + expectedOut: `PACKAGE CHANNEL BUNDLE REPLACES SKIPS SKIP RANGE IMAGE +bar beta bar.v0.1.0 <0.1.0 test.registry/bar-operator/bar-bundle:v0.1.0 +bar beta bar.v0.2.0 bar.v0.1.0 bar.v0.1.1,bar.v0.1.2 <0.2.0 test.registry/bar-operator/bar-bundle:v0.2.0 +bar stable bar.v0.2.0 bar.v0.1.0 bar.v0.1.1,bar.v0.1.2 <0.2.0 test.registry/bar-operator/bar-bundle:v0.2.0 +foo beta foo.v0.1.0 <0.1.0 test.registry/foo-operator/foo-bundle:v0.1.0 +foo beta foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +foo stable foo.v0.2.0 foo.v0.1.0 foo.v0.1.1,foo.v0.1.2 <0.2.0 test.registry/foo-operator/foo-bundle:v0.2.0 +`, + }, + { + name: "Error/UnknownIndex", + list: ListBundles{IndexReference: "unknown-index"}, + expectedErr: `render reference "unknown-index": failed to pull image "unknown-index": repository name must be canonical`, + }, + { + name: "Error/UnknownPackage", + list: ListBundles{IndexReference: "testdata/list-index", PackageName: "unknown"}, + expectedErr: `package "unknown" not found`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + res, err := s.list.Run(context.Background()) + if s.expectedErr != "" { + require.Nil(t, res) + require.EqualError(t, err, s.expectedErr) + } else { + require.NoError(t, err) + + buf := &bytes.Buffer{} + err = res.WriteColumns(buf) + require.NoError(t, err) + + require.Equal(t, s.expectedOut, buf.String()) + } + }) + } +} diff --git a/alpha/action/migrate.go b/alpha/action/migrate.go new file mode 100644 index 000000000..8122d1648 --- /dev/null +++ b/alpha/action/migrate.go @@ -0,0 +1,49 @@ +package action + +import ( + "context" + "fmt" + "os" + + "github.com/operator-framework/operator-registry/alpha/action/migrations" + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/pkg/image" +) + +type Migrate struct { + CatalogRef string + OutputDir string + Migrations *migrations.Migrations + + WriteFunc declcfg.WriteFunc + FileExt string + Registry image.Registry +} + +func (m Migrate) Run(ctx context.Context) error { + entries, err := os.ReadDir(m.OutputDir) + if err != nil && !os.IsNotExist(err) { + return err + } + if len(entries) > 0 { + return fmt.Errorf("output dir %q must be empty", m.OutputDir) + } + + r := Render{ + Refs: []string{m.CatalogRef}, + Migrations: m.Migrations, + + // Only allow catalogs to be migrated. + AllowedRefMask: RefSqliteImage | RefSqliteFile | RefDCImage | RefDCDir, + } + if m.Registry != nil { + r.Registry = m.Registry + } + + cfg, err := r.Run(ctx) + if err != nil { + return fmt.Errorf("render catalog image: %w", err) + } + + return declcfg.WriteFS(*cfg, m.OutputDir, m.WriteFunc, m.FileExt) +} diff --git a/alpha/action/migrate_test.go b/alpha/action/migrate_test.go new file mode 100644 index 000000000..a0b5d2771 --- /dev/null +++ b/alpha/action/migrate_test.go @@ -0,0 +1,484 @@ +package action_test + +import ( + "context" + "io/fs" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/action" + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/pkg/containertools" + "github.com/operator-framework/operator-registry/pkg/image" + "github.com/operator-framework/operator-registry/pkg/lib/bundle" +) + +func TestMigrate(t *testing.T) { + type spec struct { + name string + migrate action.Migrate + expectedFiles map[string]string + expectErr error + } + + sqliteBundles := map[image.Reference]string{ + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + image.SimpleReference("test.registry/bar-operator/bar-bundle:v0.1.0"): "testdata/bar-bundle-v0.1.0", + image.SimpleReference("test.registry/bar-operator/bar-bundle:v0.2.0"): "testdata/bar-bundle-v0.2.0", + } + + sqliteDBDir := t.TempDir() + dbFile := filepath.Join(sqliteDBDir, "index.db") + err := generateSqliteFile(dbFile, sqliteBundles) + require.NoError(t, err) + + reg, err := newMigrateRegistry(t, sqliteBundles) + require.NoError(t, err) + + specs := []spec{ + { + name: "SqliteImage/Success", + migrate: action.Migrate{ + CatalogRef: "test.registry/migrate/catalog:sqlite", + WriteFunc: declcfg.WriteYAML, + FileExt: ".yaml", + Registry: reg, + }, + expectedFiles: map[string]string{ + "foo/catalog.yaml": migrateFooCatalogSqlite(), + "bar/catalog.yaml": migrateBarCatalogSqlite(), + }, + }, + { + name: "SqliteFile/Success", + migrate: action.Migrate{ + CatalogRef: dbFile, + WriteFunc: declcfg.WriteYAML, + FileExt: ".yaml", + Registry: reg, + }, + expectedFiles: map[string]string{ + "foo/catalog.yaml": migrateFooCatalogSqlite(), + "bar/catalog.yaml": migrateBarCatalogSqlite(), + }, + }, + { + name: "DeclcfgImage/Success", + migrate: action.Migrate{ + CatalogRef: "test.registry/foo-operator/foo-index-declcfg:v0.2.0", + WriteFunc: declcfg.WriteYAML, + FileExt: ".yaml", + Registry: reg, + }, + expectedFiles: map[string]string{ + "foo/catalog.yaml": migrateFooCatalogFBC(), + }, + }, + { + name: "DeclcfgDir/Success", + migrate: action.Migrate{ + CatalogRef: "testdata/foo-index-v0.2.0-declcfg", + WriteFunc: declcfg.WriteYAML, + FileExt: ".yaml", + Registry: reg, + }, + expectedFiles: map[string]string{ + "foo/catalog.yaml": migrateFooCatalogFBC(), + }, + }, + { + name: "BundleImage/Failure", + migrate: action.Migrate{ + CatalogRef: "test.registry/foo-operator/foo-bundle:v0.1.0", + WriteFunc: declcfg.WriteYAML, + FileExt: ".yaml", + Registry: reg, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "SqliteImage/Success/NoMigrations", + migrate: action.Migrate{ + CatalogRef: "test.registry/migrate/catalog:sqlite", + WriteFunc: declcfg.WriteYAML, + FileExt: ".yaml", + Registry: reg, + Migrations: nil, + }, + expectedFiles: map[string]string{ + "foo/catalog.yaml": migrateFooCatalogSqlite(), + "bar/catalog.yaml": migrateBarCatalogSqlite(), + }, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + s.migrate.OutputDir = t.TempDir() + + err := s.migrate.Run(context.Background()) + require.ErrorIs(t, err, s.expectErr) + if s.expectErr != nil { + return + } + actualFS := os.DirFS(s.migrate.OutputDir) + require.NoError(t, fs.WalkDir(actualFS, ".", func(path string, d fs.DirEntry, err error) error { + require.NoError(t, err) + if d.IsDir() { + return nil + } + actualData, err := fs.ReadFile(actualFS, path) + require.NoError(t, err) + expectedData, ok := s.expectedFiles[path] + require.True(t, ok, "output directory contained unexpected file %q", path) + require.Equal(t, expectedData, string(actualData)) + return nil + })) + }) + } +} + +func newMigrateRegistry(t *testing.T, imageMap map[image.Reference]string) (image.Registry, error) { + subSqliteImage, err := generateSqliteFS(t, imageMap) + if err != nil { + return nil, err + } + + subDeclcfgImage, err := fs.Sub(declcfgImage, "testdata/foo-index-v0.2.0-declcfg") + if err != nil { + return nil, err + } + + subBundleImageV1, err := fs.Sub(bundleImageV1, "testdata/foo-bundle-v0.1.0") + if err != nil { + return nil, err + } + + reg := &image.MockRegistry{RemoteImages: map[image.Reference]*image.MockImage{ + image.SimpleReference("test.registry/migrate/catalog:sqlite"): { + Labels: map[string]string{ + containertools.DbLocationLabel: "/database/index.db", + }, + FS: subSqliteImage, + }, + image.SimpleReference("test.registry/foo-operator/foo-index-declcfg:v0.2.0"): { + Labels: map[string]string{ + "operators.operatorframework.io.index.configs.v1": "/foo", + }, + FS: subDeclcfgImage, + }, + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): { + Labels: map[string]string{ + bundle.PackageLabel: "foo", + }, + FS: subBundleImageV1, + }, + }} + + return reg, nil +} + +func migrateFooCatalogSqlite() string { + return `--- +defaultChannel: beta +name: foo +schema: olm.package +--- +entries: +- name: foo.v0.1.0 + skipRange: <0.1.0 +- name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +name: beta +package: foo +schema: olm.channel +--- +entries: +- name: foo.v0.1.0 + skipRange: <0.1.0 +- name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +name: stable +package: foo +schema: olm.channel +--- +image: test.registry/foo-operator/foo-bundle:v0.1.0 +name: foo.v0.1.0 +package: foo +properties: +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.1.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +relatedImages: +- image: test.registry/foo-operator/foo-bundle:v0.1.0 + name: "" +- image: test.registry/foo-operator/foo:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.2.0 +name: foo.v0.2.0 +package: foo +properties: +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.2.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwiaW5zdGFsbCI6eyJzcGVjIjp7ImRlcGxveW1lbnRzIjpbeyJuYW1lIjoiZm9vLW9wZXJhdG9yIiwic3BlYyI6eyJ0ZW1wbGF0ZSI6eyJzcGVjIjp7ImNvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQ6djAuMi4wIn1dfX19fSx7Im5hbWUiOiJmb28tb3BlcmF0b3ItMiIsInNwZWMiOnsidGVtcGxhdGUiOnsic3BlYyI6eyJjb250YWluZXJzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvby0yOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQtMjp2MC4yLjAifV19fX19XX0sInN0cmF0ZWd5IjoiZGVwbG95bWVudCJ9LCJyZWxhdGVkSW1hZ2VzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvbzp2MC4yLjAiLCJuYW1lIjoib3BlcmF0b3IifSx7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLW90aGVyOnYwLjIuMCIsIm5hbWUiOiJvdGhlciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 +relatedImages: +- image: test.registry/foo-operator/foo-2:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-bundle:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-init-2:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-init:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-other:v0.2.0 + name: other +- image: test.registry/foo-operator/foo:v0.2.0 + name: operator +schema: olm.bundle +` +} + +func migrateBarCatalogSqlite() string { + return `--- +defaultChannel: alpha +name: bar +schema: olm.package +--- +entries: +- name: bar.v0.1.0 +- name: bar.v0.2.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.0 +name: alpha +package: bar +schema: olm.channel +--- +image: test.registry/bar-operator/bar-bundle:v0.1.0 +name: bar.v0.1.0 +package: bar +properties: +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.1.0 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +relatedImages: +- image: test.registry/bar-operator/bar-bundle:v0.1.0 + name: "" +- image: test.registry/bar-operator/bar:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v0.2.0 +name: bar.v0.2.0 +package: bar +properties: +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.2.0 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= +relatedImages: +- image: test.registry/bar-operator/bar-bundle:v0.2.0 + name: "" +- image: test.registry/bar-operator/bar:v0.2.0 + name: operator +schema: olm.bundle +` +} + +func migrateFooCatalogFBC() string { + return `--- +defaultChannel: beta +name: foo +properties: +- type: owner + value: + group: abc.com + name: admin +schema: olm.package +--- +entries: +- name: foo.v0.1.0 + skipRange: <0.1.0 +- name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +name: beta +package: foo +properties: +- type: user + value: + group: xyz.com + name: account +schema: olm.channel +--- +entries: +- name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +name: stable +package: foo +schema: olm.channel +--- +image: test.registry/foo-operator/foo-bundle:v0.1.0 +name: foo.v0.1.0 +package: foo +properties: +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.1.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: +- image: test.registry/foo-operator/foo-bundle:v0.1.0 + name: "" +- image: test.registry/foo-operator/foo:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.2.0 +name: foo.v0.2.0 +package: foo +properties: +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.2.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwiaW5zdGFsbCI6eyJzcGVjIjp7ImRlcGxveW1lbnRzIjpbeyJuYW1lIjoiZm9vLW9wZXJhdG9yIiwic3BlYyI6eyJ0ZW1wbGF0ZSI6eyJzcGVjIjp7ImNvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQ6djAuMi4wIn1dfX19fSx7Im5hbWUiOiJmb28tb3BlcmF0b3ItMiIsInNwZWMiOnsidGVtcGxhdGUiOnsic3BlYyI6eyJjb250YWluZXJzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvby0yOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQtMjp2MC4yLjAifV19fX19XX0sInN0cmF0ZWd5IjoiZGVwbG95bWVudCJ9LCJyZWxhdGVkSW1hZ2VzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvbzp2MC4yLjAiLCJuYW1lIjoib3BlcmF0b3IifSx7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLW90aGVyOnYwLjIuMCIsIm5hbWUiOiJvdGhlciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: +- image: test.registry/foo-operator/foo-2:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-bundle:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-init-2:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-init:v0.2.0 + name: "" +- image: test.registry/foo-operator/foo-other:v0.2.0 + name: other +- image: test.registry/foo-operator/foo:v0.2.0 + name: operator +schema: olm.bundle +` +} diff --git a/alpha/action/migrations/000_bundle_object_to_csv_metadata.go b/alpha/action/migrations/000_bundle_object_to_csv_metadata.go new file mode 100644 index 000000000..d5c6896ea --- /dev/null +++ b/alpha/action/migrations/000_bundle_object_to_csv_metadata.go @@ -0,0 +1,47 @@ +package migrations + +import ( + "encoding/json" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func bundleObjectToCSVMetadata(cfg *declcfg.DeclarativeConfig) error { + convertBundleObjectToCSVMetadata := func(b *declcfg.Bundle) error { + if b.Image == "" || b.CsvJSON == "" { + return nil + } + + var csv v1alpha1.ClusterServiceVersion + if err := json.Unmarshal([]byte(b.CsvJSON), &csv); err != nil { + return err + } + + props := b.Properties[:0] + for _, p := range b.Properties { + switch p.Type { + case property.TypeBundleObject: + // Get rid of the bundle objects + case property.TypeCSVMetadata: + // If this bundle already has a CSV metadata + // property, we won't mutate the bundle at all. + return nil + default: + // Keep all of the other properties + props = append(props, p) + } + } + b.Properties = append(props, property.MustBuildCSVMetadata(csv)) + return nil + } + + for bi := range cfg.Bundles { + if err := convertBundleObjectToCSVMetadata(&cfg.Bundles[bi]); err != nil { + return err + } + } + return nil +} diff --git a/alpha/action/migrations/migrations.go b/alpha/action/migrations/migrations.go new file mode 100644 index 000000000..22ff86b74 --- /dev/null +++ b/alpha/action/migrations/migrations.go @@ -0,0 +1,104 @@ +package migrations + +import ( + "fmt" + "slices" + "strings" + "text/tabwriter" + + "github.com/operator-framework/operator-registry/alpha/declcfg" +) + +type MigrationToken string + +const ( + invalidMigration string = "" + NoMigrations string = "none" + AllMigrations string = "all" +) + +type Migration interface { + Token() MigrationToken + Help() string + Migrate(*declcfg.DeclarativeConfig) error +} + +func newMigration(token string, help string, fn func(config *declcfg.DeclarativeConfig) error) Migration { + return &simpleMigration{token: MigrationToken(token), help: help, fn: fn} +} + +type simpleMigration struct { + token MigrationToken + help string + fn func(*declcfg.DeclarativeConfig) error +} + +func (s simpleMigration) Token() MigrationToken { + return s.token +} + +func (s simpleMigration) Migrate(config *declcfg.DeclarativeConfig) error { + return s.fn(config) +} + +func (s simpleMigration) Help() string { + return s.help +} + +type Migrations struct { + Migrations []Migration +} + +// allMigrations represents the migration catalog +// the order of these migrations is important +var allMigrations = []Migration{ + newMigration(NoMigrations, "do nothing", func(_ *declcfg.DeclarativeConfig) error { return nil }), + newMigration("bundle-object-to-csv-metadata", `migrates bundles' "olm.bundle.object" to "olm.csv.metadata"`, bundleObjectToCSVMetadata), +} + +func NewMigrations(name string) (*Migrations, error) { + if name == AllMigrations { + return &Migrations{Migrations: slices.Clone(allMigrations)}, nil + } + + migrations := slices.Clone(allMigrations) + + found := false + keep := migrations[:0] + for _, migration := range migrations { + keep = append(keep, migration) + if migration.Token() == MigrationToken(name) { + found = true + break + } + } + if !found { + return nil, fmt.Errorf("unknown migration level %q", name) + } + return &Migrations{Migrations: keep}, nil +} + +func HelpText() string { + var help strings.Builder + help.WriteString("\nThe migrator will run all migrations up to and including the selected level.\n\n") + help.WriteString("Available migrators:\n") + if len(allMigrations) == 0 { + help.WriteString(" (no migrations available in this version)\n") + } + + tabber := tabwriter.NewWriter(&help, 0, 0, 1, ' ', 0) + for _, migration := range allMigrations { + fmt.Fprintf(tabber, " - %s\t: %s\n", migration.Token(), migration.Help()) + } + tabber.Flush() + return help.String() +} + +func (m *Migrations) Migrate(config *declcfg.DeclarativeConfig) error { + for _, migration := range m.Migrations { + if err := migration.Migrate(config); err != nil { + return err + } + } + return nil +} diff --git a/alpha/action/migrations/migrations_test.go b/alpha/action/migrations/migrations_test.go new file mode 100644 index 000000000..d3b1ad074 --- /dev/null +++ b/alpha/action/migrations/migrations_test.go @@ -0,0 +1,141 @@ +package migrations + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func TestMigrations(t *testing.T) { + noneMigration, err := NewMigrations(NoMigrations) + require.NoError(t, err) + csvMigration, err := NewMigrations("bundle-object-to-csv-metadata") + require.NoError(t, err) + allMigrations, err := NewMigrations(AllMigrations) + require.NoError(t, err) + + migrationPhaseEvaluators := map[MigrationToken]func(*declcfg.DeclarativeConfig) error{ + MigrationToken(NoMigrations): func(d *declcfg.DeclarativeConfig) error { + if diff := cmp.Diff(*d, unmigratedCatalogFBC()); diff != "" { + return fmt.Errorf("'none' migrator is not expected to change the config\n%s", diff) + } + return nil + }, + MigrationToken("bundle-object-to-csv-metadata"): func(d *declcfg.DeclarativeConfig) error { + if diff := cmp.Diff(*d, csvMetadataCatalogFBC()); diff != "" { + return fmt.Errorf("unexpected result of migration\n%s", diff) + } + return nil + }, + } + + tests := []struct { + name string + migrators *Migrations + }{ + { + name: "NoMigrations", + migrators: noneMigration, + }, + { + name: "BundleObjectToCSVMetadata", + migrators: csvMigration, + }, + { + name: "MigrationSequence", + migrators: allMigrations, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var config = unmigratedCatalogFBC() + + for _, m := range test.migrators.Migrations { + err := m.Migrate(&config) + require.NoError(t, err) + err = migrationPhaseEvaluators[m.Token()](&config) + require.NoError(t, err) + } + }) + } +} + +func mustBuildCSVMetadata(r io.Reader) property.Property { + var csv v1alpha1.ClusterServiceVersion + if err := json.NewDecoder(r).Decode(&csv); err != nil { + panic(err) + } + return property.MustBuildCSVMetadata(csv) +} + +var fooRawCsv = []byte(`{"apiVersion": "operators.coreos.com/v1alpha1", "kind": "ClusterServiceVersion", "metadata": {"name": "foo.v0.1.0"}, "spec": {"displayName": "Foo Operator", "customresourcedefinitions": {"owned": [{"group": "test.foo", "version": "v1", "kind": "Foo", "name": "foos.test.foo"}]}, "version": "0.1.0", "relatedImages": [{"name": "operator", "image": "test.registry/foo-operator/foo:v0.1.0"}]}}`) + +var fooRawCrd = []byte(`--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: foos.test.foo +spec: + group: test.foo + names: + kind: Foo + plural: foos + versions: + - name: v1`, +) + +func unmigratedCatalogFBC() declcfg.DeclarativeConfig { + return declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "quay.io/openshift-community-operators/foo:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(fooRawCrd), + property.MustBuildBundleObject(fooRawCsv), + }, + Objects: []string{string(fooRawCsv), string(fooRawCrd)}, + CsvJSON: string(fooRawCsv), + }, + }, + } +} + +func csvMetadataCatalogFBC() declcfg.DeclarativeConfig { + return declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "quay.io/openshift-community-operators/foo:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + mustBuildCSVMetadata(bytes.NewReader(fooRawCsv)), + }, + Objects: []string{string(fooRawCsv), string(fooRawCrd)}, + CsvJSON: string(fooRawCsv), + }, + }, + } +} diff --git a/alpha/action/render.go b/alpha/action/render.go new file mode 100644 index 000000000..a124c0f8a --- /dev/null +++ b/alpha/action/render.go @@ -0,0 +1,485 @@ +package action + +import ( + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + "sync" + "text/template" + + "github.com/h2non/filetype" + "github.com/h2non/filetype/matchers" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/operator-framework/operator-registry/alpha/action/migrations" + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" + "github.com/operator-framework/operator-registry/pkg/containertools" + "github.com/operator-framework/operator-registry/pkg/image" + "github.com/operator-framework/operator-registry/pkg/image/containersimageregistry" + "github.com/operator-framework/operator-registry/pkg/lib/bundle" + "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/operator-framework/operator-registry/pkg/sqlite" +) + +var logDeprecationMessage sync.Once + +type RefType uint + +const ( + RefBundleImage RefType = 1 << iota + RefSqliteImage + RefSqliteFile + RefDCImage + RefDCDir + RefBundleDir + + RefAll = 0 +) + +func (r RefType) Allowed(refType RefType) bool { + return r == RefAll || r&refType == refType +} + +var ErrNotAllowed = errors.New("not allowed") + +type Render struct { + Refs []string + Registry image.Registry + AllowedRefMask RefType + ImageRefTemplate *template.Template + Migrations *migrations.Migrations + + skipSqliteDeprecationLog bool +} + +func (r Render) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) { + if r.skipSqliteDeprecationLog { + // exhaust once with a no-op function. + logDeprecationMessage.Do(func() {}) + } + if r.Registry == nil { + reg, err := containersimageregistry.NewDefault() + if err != nil { + return nil, fmt.Errorf("create registry: %v", err) + } + defer func() { + _ = reg.Destroy() + }() + r.Registry = reg + } + + // nolint:prealloc + var cfgs []declcfg.DeclarativeConfig + for _, ref := range r.Refs { + cfg, err := r.renderReference(ctx, ref) + if err != nil { + return nil, fmt.Errorf("render reference %q: %w", ref, err) + } + moveBundleObjectsToEndOfPropertySlices(cfg) + + for _, b := range cfg.Bundles { + sort.Slice(b.RelatedImages, func(i, j int) bool { + return b.RelatedImages[i].Image < b.RelatedImages[j].Image + }) + } + + if err := r.migrate(cfg); err != nil { + return nil, fmt.Errorf("migrate: %v", err) + } + + cfgs = append(cfgs, *cfg) + } + + return combineConfigs(cfgs), nil +} + +func (r Render) renderReference(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) { + stat, err := os.Stat(ref) + if err != nil { + return r.imageToDeclcfg(ctx, ref) + } + // nolint:nestif + if stat.IsDir() { + dirEntries, err := os.ReadDir(ref) + if err != nil { + return nil, err + } + if isBundle(dirEntries) { + // Looks like a bundle directory + if !r.AllowedRefMask.Allowed(RefBundleDir) { + return nil, fmt.Errorf("cannot render bundle directory %q: %w", ref, ErrNotAllowed) + } + return r.renderBundleDirectory(ref) + } + + // Otherwise, assume it is a declarative config root directory. + if !r.AllowedRefMask.Allowed(RefDCDir) { + return nil, fmt.Errorf("cannot render declarative config directory: %w", ErrNotAllowed) + } + return declcfg.LoadFS(ctx, os.DirFS(ref)) + } + // The only supported file type is an sqlite DB file, + // since declarative configs will be in a directory. + if err := checkDBFile(ref); err != nil { + return nil, err + } + if !r.AllowedRefMask.Allowed(RefSqliteFile) { + return nil, fmt.Errorf("cannot render sqlite file: %w", ErrNotAllowed) + } + + db, err := sqlite.Open(ref) + if err != nil { + return nil, err + } + defer db.Close() + return sqliteToDeclcfg(ctx, db) +} + +func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.DeclarativeConfig, error) { + ref := image.SimpleReference(imageRef) + if err := r.Registry.Pull(ctx, ref); err != nil { + return nil, fmt.Errorf("failed to pull image %q: %v", ref, err) + } + labels, err := r.Registry.Labels(ctx, ref) + if err != nil { + return nil, fmt.Errorf("failed to get labels for image %q: %v", ref, err) + } + tmpDir, err := os.MkdirTemp("", "render-unpack-") + if err != nil { + return nil, fmt.Errorf("create tempdir: %v", err) + } + defer os.RemoveAll(tmpDir) + if err := r.Registry.Unpack(ctx, ref, tmpDir); err != nil { + return nil, fmt.Errorf("failed to unpack image %q: %v", ref, err) + } + + var cfg *declcfg.DeclarativeConfig + // nolint:nestif + if dbFile, ok := labels[containertools.DbLocationLabel]; ok { + if !r.AllowedRefMask.Allowed(RefSqliteImage) { + return nil, fmt.Errorf("cannot render sqlite image: %w", ErrNotAllowed) + } + db, err := sqlite.Open(filepath.Join(tmpDir, dbFile)) + if err != nil { + return nil, err + } + defer db.Close() + cfg, err = sqliteToDeclcfg(ctx, db) + if err != nil { + return nil, err + } + } else if configsDir, ok := labels[containertools.ConfigsLocationLabel]; ok { + if !r.AllowedRefMask.Allowed(RefDCImage) { + return nil, fmt.Errorf("cannot render declarative config image: %w", ErrNotAllowed) + } + cfg, err = declcfg.LoadFS(ctx, os.DirFS(filepath.Join(tmpDir, configsDir))) + if err != nil { + return nil, err + } + } else if _, ok := labels[bundle.PackageLabel]; ok { + if !r.AllowedRefMask.Allowed(RefBundleImage) { + return nil, fmt.Errorf("cannot render bundle image: %w", ErrNotAllowed) + } + img, err := registry.NewImageInput(ref, tmpDir) + if err != nil { + return nil, err + } + + bundle, err := bundleToDeclcfg(img.Bundle) + if err != nil { + return nil, err + } + cfg = &declcfg.DeclarativeConfig{Bundles: []declcfg.Bundle{*bundle}} + } else { + labelKeys := sets.StringKeySet(labels) + labelVals := []string{} + for _, k := range labelKeys.List() { + labelVals = append(labelVals, fmt.Sprintf(" %s=%s", k, labels[k])) + } + if len(labelVals) > 0 { + return nil, fmt.Errorf("render %q: image type could not be determined, found labels\n%s", ref, strings.Join(labelVals, "\n")) + } else { + return nil, fmt.Errorf("render %q: image type could not be determined: image has no labels", ref) + } + } + return cfg, nil +} + +// checkDBFile returns an error if ref is not an sqlite3 database. +func checkDBFile(ref string) error { + typ, err := filetype.MatchFile(ref) + if err != nil { + return err + } + if typ != matchers.TypeSqlite { + return fmt.Errorf("ref %q has unsupported file type: %s", ref, typ) + } + return nil +} + +func sqliteToDeclcfg(ctx context.Context, db *sql.DB) (*declcfg.DeclarativeConfig, error) { + logDeprecationMessage.Do(func() { + sqlite.LogSqliteDeprecation() + }) + + migrator, err := sqlite.NewSQLLiteMigrator(db) + if err != nil { + return nil, err + } + if migrator == nil { + return nil, fmt.Errorf("failed to load migrator") + } + + if err := migrator.Migrate(ctx); err != nil { + return nil, err + } + + q := sqlite.NewSQLLiteQuerierFromDb(db) + m, err := sqlite.ToModel(ctx, q) + if err != nil { + return nil, err + } + + cfg := declcfg.ConvertFromModel(m) + + if err := populateDBRelatedImages(ctx, &cfg, db); err != nil { + return nil, err + } + + return &cfg, nil +} + +func populateDBRelatedImages(ctx context.Context, cfg *declcfg.DeclarativeConfig, db *sql.DB) error { + rows, err := db.QueryContext(ctx, "SELECT image, operatorbundle_name FROM related_image") + if err != nil { + return err + } + defer rows.Close() + + // nolint:staticcheck + images := map[string]sets.String{} + for rows.Next() { + var ( + img sql.NullString + bundleName sql.NullString + ) + if err := rows.Scan(&img, &bundleName); err != nil { + return err + } + if !img.Valid || !bundleName.Valid { + continue + } + m, ok := images[bundleName.String] + if !ok { + m = sets.NewString() + } + m.Insert(img.String) + images[bundleName.String] = m + } + + for i, b := range cfg.Bundles { + ris, ok := images[b.Name] + if !ok { + continue + } + for _, ri := range b.RelatedImages { + if ris.Has(ri.Image) { + ris.Delete(ri.Image) + } + } + for ri := range ris { + cfg.Bundles[i].RelatedImages = append(cfg.Bundles[i].RelatedImages, declcfg.RelatedImage{Image: ri}) + } + } + return nil +} + +func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.Bundle, error) { + objs, props, err := registry.ObjectsAndPropertiesFromBundle(bundle) + if err != nil { + return nil, fmt.Errorf("get properties for bundle %q: %v", bundle.Name, err) + } + relatedImages, err := getRelatedImages(bundle) + if err != nil { + return nil, fmt.Errorf("get related images for bundle %q: %v", bundle.Name, err) + } + + var csvJSON []byte + for _, obj := range bundle.Objects { + if obj.GetKind() == "ClusterServiceVersion" { + csvJSON, err = json.Marshal(obj) + if err != nil { + return nil, fmt.Errorf("marshal CSV JSON for bundle %q: %v", bundle.Name, err) + } + } + } + + return &declcfg.Bundle{ + Schema: "olm.bundle", + Name: bundle.Name, + Package: bundle.Package, + Image: bundle.BundleImage, + Properties: props, + RelatedImages: relatedImages, + Objects: objs, + CsvJSON: string(csvJSON), + }, nil +} + +func getRelatedImages(b *registry.Bundle) ([]declcfg.RelatedImage, error) { + csv, err := b.ClusterServiceVersion() + if err != nil { + return nil, err + } + + var objmap map[string]*json.RawMessage + if err = json.Unmarshal(csv.Spec, &objmap); err != nil { + return nil, err + } + + var relatedImages []declcfg.RelatedImage + rawValue, ok := objmap["relatedImages"] + if ok && rawValue != nil { + if err = json.Unmarshal(*rawValue, &relatedImages); err != nil { + return nil, err + } + } + + // Keep track of the images we've already found, so that we don't add + // them multiple times. + allImages := sets.NewString() + for _, ri := range relatedImages { + allImages = allImages.Insert(ri.Image) + } + + if b.BundleImage != "" && !allImages.Has(b.BundleImage) { + relatedImages = append(relatedImages, declcfg.RelatedImage{ + Image: b.BundleImage, + }) + } + + opImages, err := csv.GetOperatorImages() + if err != nil { + return nil, err + } + for img := range opImages { + if !allImages.Has(img) { + relatedImages = append(relatedImages, declcfg.RelatedImage{ + Image: img, + }) + } + allImages = allImages.Insert(img) + } + + return relatedImages, nil +} + +func moveBundleObjectsToEndOfPropertySlices(cfg *declcfg.DeclarativeConfig) { + for bi, b := range cfg.Bundles { + var ( + others []property.Property + objs []property.Property + ) + for _, p := range b.Properties { + switch p.Type { + case property.TypeBundleObject, property.TypeCSVMetadata: + objs = append(objs, p) + default: + others = append(others, p) + } + } + cfg.Bundles[bi].Properties = append(others, objs...) + } +} + +func (r Render) migrate(cfg *declcfg.DeclarativeConfig) error { + // If there are no migrations, do nothing. + if r.Migrations == nil { + return nil + } + return r.Migrations.Migrate(cfg) +} + +func combineConfigs(cfgs []declcfg.DeclarativeConfig) *declcfg.DeclarativeConfig { + out := &declcfg.DeclarativeConfig{} + for _, in := range cfgs { + out.Merge(&in) + } + return out +} + +func isBundle(entries []os.DirEntry) bool { + foundManifests := false + foundMetadata := false + for _, e := range entries { + if e.IsDir() { + switch e.Name() { + case "manifests": + foundManifests = true + case "metadata": + foundMetadata = true + } + } + if foundMetadata && foundManifests { + return true + } + } + return false +} + +type imageReferenceTemplateData struct { + Package string + Name string + Version string +} + +func (r *Render) renderBundleDirectory(ref string) (*declcfg.DeclarativeConfig, error) { + img, err := registry.NewImageInput(image.SimpleReference(""), ref) + if err != nil { + return nil, err + } + if err := r.templateBundleImageRef(img.Bundle); err != nil { + return nil, fmt.Errorf("failed templating image reference from bundle for %q: %v", ref, err) + } + fbcBundle, err := bundleToDeclcfg(img.Bundle) + if err != nil { + return nil, err + } + return &declcfg.DeclarativeConfig{Bundles: []declcfg.Bundle{*fbcBundle}}, nil +} + +func (r *Render) templateBundleImageRef(bundle *registry.Bundle) error { + if r.ImageRefTemplate == nil { + return nil + } + + var pkgProp property.Package + for _, p := range bundle.Properties { + if p.Type != property.TypePackage { + continue + } + if err := json.Unmarshal(p.Value, &pkgProp); err != nil { + return err + } + break + } + + var buf strings.Builder + tmplInput := imageReferenceTemplateData{ + Package: bundle.Package, + Name: bundle.Name, + Version: pkgProp.Version, + } + if err := r.ImageRefTemplate.Execute(&buf, tmplInput); err != nil { + return err + } + bundle.BundleImage = buf.String() + return nil +} diff --git a/alpha/action/render_test.go b/alpha/action/render_test.go new file mode 100644 index 000000000..72fdd8a4e --- /dev/null +++ b/alpha/action/render_test.go @@ -0,0 +1,1562 @@ +package action_test + +import ( + "context" + "embed" + "encoding/json" + "fmt" + "io/fs" + "os" + "path/filepath" + "testing" + "testing/fstest" + "text/template" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/operator-framework/operator-registry/alpha/action" + "github.com/operator-framework/operator-registry/alpha/action/migrations" + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" + "github.com/operator-framework/operator-registry/pkg/containertools" + "github.com/operator-framework/operator-registry/pkg/image" + "github.com/operator-framework/operator-registry/pkg/lib/bundle" + "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/operator-framework/operator-registry/pkg/sqlite" +) + +type fauxMigration struct { + token string + help string + migrate func(*declcfg.DeclarativeConfig) error +} + +func (m fauxMigration) Token() migrations.MigrationToken { + return migrations.MigrationToken(m.token) +} +func (m fauxMigration) Help() string { + return m.help +} +func (m fauxMigration) Migrate(config *declcfg.DeclarativeConfig) error { + return m.migrate(config) +} + +func TestRender(t *testing.T) { + type spec struct { + name string + render action.Render + expectCfg *declcfg.DeclarativeConfig + assertion require.ErrorAssertionFunc + } + + reg, err := newRegistry(t) + require.NoError(t, err) + foov1csv, err := bundleImageV1.ReadFile("testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml") + require.NoError(t, err) + foov1crd, err := bundleImageV1.ReadFile("testdata/foo-bundle-v0.1.0/manifests/foos.test.foo.crd.yaml") + require.NoError(t, err) + foov2csv, err := bundleImageV2.ReadFile("testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml") + require.NoError(t, err) + foov2crd, err := bundleImageV2.ReadFile("testdata/foo-bundle-v0.2.0/manifests/foos.test.foo.crd.yaml") + require.NoError(t, err) + foov2csvNoRelatedImages, err := bundleImageV2NoCSVRelatedImages.ReadFile("testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foo.v0.2.0.csv.yaml") + require.NoError(t, err) + foov2crdNoRelatedImages, err := bundleImageV2NoCSVRelatedImages.ReadFile("testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foos.test.foo.crd.yaml") + require.NoError(t, err) + + foov1csv, err = yaml.ToJSON(foov1csv) + require.NoError(t, err) + foov1crd, err = yaml.ToJSON(foov1crd) + require.NoError(t, err) + foov2csv, err = yaml.ToJSON(foov2csv) + require.NoError(t, err) + foov2crd, err = yaml.ToJSON(foov2crd) + require.NoError(t, err) + foov2csvNoRelatedImages, err = yaml.ToJSON(foov2csvNoRelatedImages) + require.NoError(t, err) + foov2crdNoRelatedImages, err = yaml.ToJSON(foov2crdNoRelatedImages) + require.NoError(t, err) + + dir := t.TempDir() + dbFile := filepath.Join(dir, "index.db") + imageMap := map[image.Reference]string{ + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + } + require.NoError(t, generateSqliteFile(dbFile, imageMap)) + testMigrations := migrations.Migrations{ + Migrations: []migrations.Migration{ + fauxMigration{"faux-migration", "my help text", func(d *declcfg.DeclarativeConfig) error { + for i := range d.Bundles { + d.Bundles[i].Name = fmt.Sprintf("%s-MIGRATED", d.Bundles[i].Name) + } + return nil + }}, + }, + } + + specs := []spec{ + { + name: "Success/SqliteIndexImage", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1crd), + property.MustBuildBundleObject(foov1csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/SqliteIndexImageWithMigration", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"}, + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1crd), + property.MustBuildBundleObject(foov1csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/SqliteFile", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1crd), + property.MustBuildBundleObject(foov1csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/SqliteFileMigration", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1crd), + property.MustBuildBundleObject(foov1csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/DeclcfgIndexImage", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + Properties: []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }, + Properties: []property.Property{ + {Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")}, + }, + }, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1csv), + property.MustBuildBundleObject(foov1crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2csv), + property.MustBuildBundleObject(foov2crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/DeclcfgDirectory", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + Properties: []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }, + Properties: []property.Property{ + {Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")}, + }, + }, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1csv), + property.MustBuildBundleObject(foov1crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2csv), + property.MustBuildBundleObject(foov2crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/DeclcfgImageMigrate", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"}, + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + Properties: []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }, + Properties: []property.Property{ + {Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")}, + }, + }, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1csv), + property.MustBuildBundleObject(foov1crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2csv), + property.MustBuildBundleObject(foov2crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/DeclcfgDirectoryMigrate", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "foo", + DefaultChannel: "beta", + Properties: []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + }, + }, + Channels: []declcfg.Channel{ + {Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.1.0", SkipRange: "<0.1.0"}, + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }, + Properties: []property.Property{ + {Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")}, + }, + }, + {Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{ + {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}}, + }}, + }, + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.1.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov1csv), + property.MustBuildBundleObject(foov1crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-bundle:v0.1.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.1.0", + }, + }, + CsvJSON: string(foov1csv), + Objects: []string{string(foov1csv), string(foov1crd)}, + }, + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2csv), + property.MustBuildBundleObject(foov2crd), + }, + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + CsvJSON: string(foov2csv), + Objects: []string{string(foov2csv), string(foov2crd)}, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleImage", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle:v0.2.0"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + Objects: []string{string(foov2csv), string(foov2crd)}, + CsvJSON: string(foov2csv), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleImageMigration", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle:v0.2.0"}, + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + Objects: []string{string(foov2csv), string(foov2crd)}, + CsvJSON: string(foov2csv), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleImageWithNoCSVRelatedImages", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crdNoRelatedImages), + property.MustBuildBundleObject(foov2csvNoRelatedImages), + }, + Objects: []string{string(foov2csvNoRelatedImages), string(foov2crdNoRelatedImages)}, + CsvJSON: string(foov2csvNoRelatedImages), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleImageWithNoCSVRelatedImagesMigration", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0"}, + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csvNoRelatedImages), + }, + Objects: []string{string(foov2csvNoRelatedImages), string(foov2crdNoRelatedImages)}, + CsvJSON: string(foov2csvNoRelatedImages), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleDirectoryWithImageRefTemplate", + render: action.Render{ + Refs: []string{"testdata/foo-bundle-v0.2.0"}, + ImageRefTemplate: template.Must(template.New("imageRef").Parse("test.registry/{{.Package}}-operator/{{.Package}}:v{{.Version}}")), + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Image: "test.registry/foo-operator/foo:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + Objects: []string{string(foov2csv), string(foov2crd)}, + CsvJSON: string(foov2csv), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleDirectoryWithImageRefTemplateMigration", + render: action.Render{ + Refs: []string{"testdata/foo-bundle-v0.2.0"}, + ImageRefTemplate: template.Must(template.New("imageRef").Parse("test.registry/{{.Package}}-operator/{{.Package}}:v{{.Version}}")), + Registry: reg, + Migrations: &testMigrations, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0-MIGRATED", + Package: "foo", + Image: "test.registry/foo-operator/foo:v0.2.0", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + Objects: []string{string(foov2csv), string(foov2crd)}, + CsvJSON: string(foov2csv), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + { + name: "Success/BundleDirectory", + render: action.Render{ + Refs: []string{"testdata/foo-bundle-v0.2.0"}, + Registry: reg, + }, + expectCfg: &declcfg.DeclarativeConfig{ + Bundles: []declcfg.Bundle{ + { + Schema: "olm.bundle", + Name: "foo.v0.2.0", + Package: "foo", + Properties: []property.Property{ + property.MustBuildGVK("test.foo", "v1", "Foo"), + property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"), + property.MustBuildPackage("foo", "0.2.0"), + property.MustBuildPackageRequired("bar", "<0.1.0"), + property.MustBuildBundleObject(foov2crd), + property.MustBuildBundleObject(foov2csv), + }, + Objects: []string{string(foov2csv), string(foov2crd)}, + CsvJSON: string(foov2csv), + RelatedImages: []declcfg.RelatedImage{ + { + Image: "test.registry/foo-operator/foo-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init-2:v0.2.0", + }, + { + Image: "test.registry/foo-operator/foo-init:v0.2.0", + }, + { + Name: "other", + Image: "test.registry/foo-operator/foo-other:v0.2.0", + }, + { + Name: "operator", + Image: "test.registry/foo-operator/foo:v0.2.0", + }, + }, + }, + }, + }, + assertion: require.NoError, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + actualCfg, actualErr := s.render.Run(context.Background()) + s.assertion(t, actualErr) + require.Equal(t, len(s.expectCfg.Packages), len(actualCfg.Packages)) + require.Equal(t, s.expectCfg.Packages, actualCfg.Packages) + require.Equal(t, len(s.expectCfg.Channels), len(actualCfg.Channels)) + require.Equal(t, s.expectCfg.Channels, actualCfg.Channels) + require.Equal(t, len(s.expectCfg.Bundles), len(actualCfg.Bundles)) + for i := range s.expectCfg.Bundles { + actual, expected := actualCfg.Bundles[i], s.expectCfg.Bundles[i] + require.Equal(t, expected, actual, "bundle %d", i) + } + require.Equal(t, len(s.expectCfg.Others), len(actualCfg.Others)) + require.Equal(t, s.expectCfg.Others, actualCfg.Others) + }) + } +} + +func TestAllowRefMask(t *testing.T) { + type spec struct { + name string + render action.Render + expectErr error + } + + reg, err := newRegistry(t) + require.NoError(t, err) + + dir := t.TempDir() + dbFile := filepath.Join(dir, "index.db") + imageMap := map[image.Reference]string{ + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + } + require.NoError(t, generateSqliteFile(dbFile, imageMap)) + + specs := []spec{ + { + name: "SqliteImage/Allowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefSqliteImage, + }, + expectErr: nil, + }, + { + name: "SqliteImage/NotAllowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteFile | action.RefBundleImage | action.RefBundleDir, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "SqliteFile/Allowed", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + AllowedRefMask: action.RefSqliteFile, + }, + expectErr: nil, + }, + { + name: "SqliteFile/NotAllowed", + render: action.Render{ + Refs: []string{dbFile}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefBundleImage | action.RefBundleDir, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "DeclcfgImage/Allowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage, + }, + expectErr: nil, + }, + { + name: "DeclcfgImage/NotAllowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage | action.RefBundleDir, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "DeclcfgDir/Allowed", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + AllowedRefMask: action.RefDCDir, + }, + expectErr: nil, + }, + { + name: "DeclcfgDir/NotAllowed", + render: action.Render{ + Refs: []string{"testdata/foo-index-v0.2.0-declcfg"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage | action.RefBundleDir, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "BundleImage/Allowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefBundleImage, + }, + expectErr: nil, + }, + { + name: "BundleImage/NotAllowed", + render: action.Render{ + Refs: []string{"test.registry/foo-operator/foo-bundle:v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleDir, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "BundleDir/Allowed", + render: action.Render{ + Refs: []string{"testdata/foo-bundle-v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefBundleDir, + }, + expectErr: nil, + }, + { + name: "BundleDir/NotAllowed", + render: action.Render{ + Refs: []string{"testdata/foo-bundle-v0.2.0"}, + Registry: reg, + AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage, + }, + expectErr: action.ErrNotAllowed, + }, + { + name: "All/Allowed", + render: action.Render{ + Refs: []string{ + "test.registry/foo-operator/foo-index-sqlite:v0.2.0", + dbFile, + "test.registry/foo-operator/foo-index-declcfg:v0.2.0", + "testdata/foo-index-v0.2.0-declcfg", + "test.registry/foo-operator/foo-bundle:v0.2.0", + "testdata/foo-bundle-v0.2.0", + }, + Registry: reg, + }, + expectErr: nil, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + _, err := s.render.Run(context.Background()) + require.ErrorIs(t, err, s.expectErr, "expected error %#v to be %#v", err, s.expectErr) + }) + } +} + +func TestAllowRefMaskAllowed(t *testing.T) { + type spec struct { + name string + mask action.RefType + pass []action.RefType + fail []action.RefType + } + + specs := []spec{ + { + name: "Mask/All", + mask: action.RefAll, + pass: []action.RefType{ + action.RefDCImage, + action.RefDCDir, + action.RefSqliteImage, + action.RefSqliteFile, + action.RefBundleImage, + action.RefBundleDir, + }, + fail: []action.RefType{}, + }, + { + name: "Mask/One", + mask: action.RefDCImage, + pass: []action.RefType{ + action.RefDCImage, + }, + fail: []action.RefType{ + action.RefDCDir, + action.RefSqliteImage, + action.RefSqliteFile, + action.RefBundleImage, + }, + }, + { + name: "Mask/Some", + mask: action.RefDCImage | action.RefDCDir, + pass: []action.RefType{ + action.RefDCImage, + action.RefDCDir, + }, + fail: []action.RefType{ + action.RefSqliteImage, + action.RefSqliteFile, + action.RefBundleImage, + }, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + for _, c := range s.pass { + actual := s.mask.Allowed(c) + require.True(t, actual) + } + for _, c := range s.fail { + actual := s.mask.Allowed(c) + require.False(t, actual) + } + }) + } +} + +//go:embed testdata/foo-bundle-v0.1.0/manifests/* +//go:embed testdata/foo-bundle-v0.1.0/metadata/* +var bundleImageV1 embed.FS + +//go:embed testdata/foo-bundle-v0.2.0/manifests/* +//go:embed testdata/foo-bundle-v0.2.0/metadata/* +var bundleImageV2 embed.FS + +//go:embed testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/* +//go:embed testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/* +var bundleImageV2NoCSVRelatedImages embed.FS + +//go:embed testdata/foo-index-v0.2.0-declcfg/foo/* +var declcfgImage embed.FS + +func newRegistry(t *testing.T) (image.Registry, error) { + imageMap := map[image.Reference]string{ + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0", + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0", + } + + subSqliteImage, err := generateSqliteFS(t, imageMap) + if err != nil { + return nil, err + } + subDeclcfgImage, err := fs.Sub(declcfgImage, "testdata/foo-index-v0.2.0-declcfg") + if err != nil { + return nil, err + } + subBundleImageV1, err := fs.Sub(bundleImageV1, "testdata/foo-bundle-v0.1.0") + if err != nil { + return nil, err + } + subBundleImageV2, err := fs.Sub(bundleImageV2, "testdata/foo-bundle-v0.2.0") + if err != nil { + return nil, err + } + subBundleImageV2NoCSVRelatedImages, err := fs.Sub(bundleImageV2NoCSVRelatedImages, "testdata/foo-bundle-v0.2.0-no-csv-related-images") + if err != nil { + return nil, err + } + return &image.MockRegistry{ + RemoteImages: map[image.Reference]*image.MockImage{ + image.SimpleReference("test.registry/foo-operator/foo-index-sqlite:v0.2.0"): { + Labels: map[string]string{ + containertools.DbLocationLabel: "/database/index.db", + }, + FS: subSqliteImage, + }, + image.SimpleReference("test.registry/foo-operator/foo-index-declcfg:v0.2.0"): { + Labels: map[string]string{ + "operators.operatorframework.io.index.configs.v1": "/foo", + }, + FS: subDeclcfgImage, + }, + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): { + Labels: map[string]string{ + bundle.PackageLabel: "foo", + }, + FS: subBundleImageV1, + }, + image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): { + Labels: map[string]string{ + bundle.PackageLabel: "foo", + }, + FS: subBundleImageV2, + }, + image.SimpleReference("test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0"): { + Labels: map[string]string{ + bundle.PackageLabel: "foo", + }, + FS: subBundleImageV2NoCSVRelatedImages, + }, + }, + }, nil +} + +func generateSqliteFS(t *testing.T, imageMap map[image.Reference]string) (fs.FS, error) { + dir := t.TempDir() + + dbFile := filepath.Join(dir, "index.db") + if err := generateSqliteFile(dbFile, imageMap); err != nil { + return nil, err + } + + dbData, err := os.ReadFile(dbFile) + if err != nil { + return nil, err + } + + return &fstest.MapFS{ + "database/index.db": &fstest.MapFile{ + Data: dbData, + }, + }, nil +} + +func generateSqliteFile(path string, imageMap map[image.Reference]string) error { + db, err := sqlite.Open(path) + if err != nil { + return err + } + defer db.Close() + + m, err := sqlite.NewSQLLiteMigrator(db) + if err != nil { + return err + } + if err := m.Migrate(context.Background()); err != nil { + return err + } + + graphLoader, err := sqlite.NewSQLGraphLoaderFromDB(db) + if err != nil { + return err + } + dbQuerier := sqlite.NewSQLLiteQuerierFromDb(db) + + loader, err := sqlite.NewSQLLiteLoader(db) + if err != nil { + return err + } + + populator := registry.NewDirectoryPopulator(loader, graphLoader, dbQuerier, imageMap, nil) + if err := populator.Populate(registry.ReplacesMode); err != nil { + return err + } + return nil +} diff --git a/alpha/action/testdata/bar-bundle-v0.1.0/bundle.Dockerfile b/alpha/action/testdata/bar-bundle-v0.1.0/bundle.Dockerfile new file mode 100644 index 000000000..0c32642a1 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.1.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=bar +LABEL operators.operatorframework.io.bundle.channels.v1=alpha + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/bar-bundle-v0.1.0/manifests/bar.csv.yaml b/alpha/action/testdata/bar-bundle-v0.1.0/manifests/bar.csv.yaml new file mode 100644 index 000000000..3550e4950 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.1.0/manifests/bar.csv.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: bar.v0.1.0 +spec: + customresourcedefinitions: + owned: + - group: test.bar + version: v1alpha1 + kind: Bar + name: bars.test.bar + version: 0.1.0 + relatedImages: + - name: operator + image: test.registry/bar-operator/bar:v0.1.0 diff --git a/alpha/action/testdata/bar-bundle-v0.1.0/manifests/bars.test.bar.crd.yaml b/alpha/action/testdata/bar-bundle-v0.1.0/manifests/bars.test.bar.crd.yaml new file mode 100644 index 000000000..45d703e76 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.1.0/manifests/bars.test.bar.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bars.test.bar +spec: + group: test.bar + names: + kind: Bar + plural: bars + versions: + - name: v1alpha1 diff --git a/alpha/action/testdata/bar-bundle-v0.1.0/metadata/annotations.yaml b/alpha/action/testdata/bar-bundle-v0.1.0/metadata/annotations.yaml new file mode 100644 index 000000000..e85bbf677 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.1.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: bar + operators.operatorframework.io.bundle.channels.v1: alpha + operators.operatorframework.io.bundle.channel.default.v1: alpha diff --git a/alpha/action/testdata/bar-bundle-v0.2.0/bundle.Dockerfile b/alpha/action/testdata/bar-bundle-v0.2.0/bundle.Dockerfile new file mode 100644 index 000000000..0c32642a1 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.2.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=bar +LABEL operators.operatorframework.io.bundle.channels.v1=alpha + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/bar-bundle-v0.2.0/manifests/bar.csv.yaml b/alpha/action/testdata/bar-bundle-v0.2.0/manifests/bar.csv.yaml new file mode 100644 index 000000000..7a4bc1b31 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.2.0/manifests/bar.csv.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: bar.v0.2.0 + annotations: + olm.skipRange: <0.2.0 +spec: + customresourcedefinitions: + owned: + - group: test.bar + version: v1alpha1 + kind: Bar + name: bars.test.bar + version: 0.2.0 + skips: + - bar.v0.1.0 + relatedImages: + - name: operator + image: test.registry/bar-operator/bar:v0.2.0 diff --git a/alpha/action/testdata/bar-bundle-v0.2.0/manifests/bars.test.bar.crd.yaml b/alpha/action/testdata/bar-bundle-v0.2.0/manifests/bars.test.bar.crd.yaml new file mode 100644 index 000000000..45d703e76 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.2.0/manifests/bars.test.bar.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bars.test.bar +spec: + group: test.bar + names: + kind: Bar + plural: bars + versions: + - name: v1alpha1 diff --git a/alpha/action/testdata/bar-bundle-v0.2.0/metadata/annotations.yaml b/alpha/action/testdata/bar-bundle-v0.2.0/metadata/annotations.yaml new file mode 100644 index 000000000..e85bbf677 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v0.2.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: bar + operators.operatorframework.io.bundle.channels.v1: alpha + operators.operatorframework.io.bundle.channel.default.v1: alpha diff --git a/alpha/action/testdata/bar-bundle-v1.0.0/bundle.Dockerfile b/alpha/action/testdata/bar-bundle-v1.0.0/bundle.Dockerfile new file mode 100644 index 000000000..bf252f160 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v1.0.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=bar +LABEL operators.operatorframework.io.bundle.channels.v1=stable + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/bar-bundle-v1.0.0/manifests/bar.csv.yaml b/alpha/action/testdata/bar-bundle-v1.0.0/manifests/bar.csv.yaml new file mode 100644 index 000000000..9924b1adb --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v1.0.0/manifests/bar.csv.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: bar.v1.0.0 +spec: + customresourcedefinitions: + owned: + - group: test.bar + version: v1alpha1 + kind: Bar + name: bars.test.bar + - group: test.bar + version: v1 + kind: Bar + name: bars.test.bar + version: 1.0.0 + replaces: bar.v0.2.0 + relatedImages: + - name: operator + image: test.registry/bar-operator/bar:v1.0.0 diff --git a/alpha/action/testdata/bar-bundle-v1.0.0/manifests/bars.test.bar.crd.yaml b/alpha/action/testdata/bar-bundle-v1.0.0/manifests/bars.test.bar.crd.yaml new file mode 100644 index 000000000..413f7a544 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v1.0.0/manifests/bars.test.bar.crd.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bars.test.bar +spec: + group: test.bar + names: + kind: Bar + plural: bars + versions: + - name: v1alpha1 + served: true + storage: false + - name: v1 + served: true + storage: true diff --git a/alpha/action/testdata/bar-bundle-v1.0.0/metadata/annotations.yaml b/alpha/action/testdata/bar-bundle-v1.0.0/metadata/annotations.yaml new file mode 100644 index 000000000..2b425eae5 --- /dev/null +++ b/alpha/action/testdata/bar-bundle-v1.0.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: bar + operators.operatorframework.io.bundle.channels.v1: stable + operators.operatorframework.io.bundle.channel.default.v1: stable diff --git a/alpha/action/testdata/baz-bundle-v1.0.0/bundle.Dockerfile b/alpha/action/testdata/baz-bundle-v1.0.0/bundle.Dockerfile new file mode 100644 index 000000000..5351aff0b --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=baz +LABEL operators.operatorframework.io.bundle.channels.v1=stable + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/baz-bundle-v1.0.0/manifests/baz.csv.yaml b/alpha/action/testdata/baz-bundle-v1.0.0/manifests/baz.csv.yaml new file mode 100644 index 000000000..681ae352d --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.0/manifests/baz.csv.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: baz.v1.0.0 +spec: + customresourcedefinitions: + owned: + - group: test.baz + version: v1 + kind: Baz + name: bazs.test.baz + version: 1.0.0 + relatedImages: + - name: operator + image: test.registry/baz-operator/baz:v1.0.0 diff --git a/alpha/action/testdata/baz-bundle-v1.0.0/manifests/bazs.test.baz.crd.yaml b/alpha/action/testdata/baz-bundle-v1.0.0/manifests/bazs.test.baz.crd.yaml new file mode 100644 index 000000000..757fde072 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.0/manifests/bazs.test.baz.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bazs.test.baz +spec: + group: test.baz + names: + kind: Baz + plural: bazs + versions: + - name: v1 diff --git a/alpha/action/testdata/baz-bundle-v1.0.0/metadata/annotations.yaml b/alpha/action/testdata/baz-bundle-v1.0.0/metadata/annotations.yaml new file mode 100644 index 000000000..23fcd1406 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: baz + operators.operatorframework.io.bundle.channels.v1: stable + operators.operatorframework.io.bundle.channel.default.v1: stable diff --git a/alpha/action/testdata/baz-bundle-v1.0.1/bundle.Dockerfile b/alpha/action/testdata/baz-bundle-v1.0.1/bundle.Dockerfile new file mode 100644 index 000000000..5351aff0b --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.1/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=baz +LABEL operators.operatorframework.io.bundle.channels.v1=stable + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/baz-bundle-v1.0.1/manifests/baz.csv.yaml b/alpha/action/testdata/baz-bundle-v1.0.1/manifests/baz.csv.yaml new file mode 100644 index 000000000..0d83700cd --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.1/manifests/baz.csv.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: baz.v1.0.1 + annotations: + olm.skipRange: <1.0.1 +spec: + customresourcedefinitions: + owned: + - group: test.baz + version: v1 + kind: Baz + name: bazs.test.baz + version: 1.0.1 + skips: + - baz.v1.0.0 + relatedImages: + - name: operator + image: test.registry/baz-operator/baz:v1.0.1 diff --git a/alpha/action/testdata/baz-bundle-v1.0.1/manifests/bazs.test.baz.crd.yaml b/alpha/action/testdata/baz-bundle-v1.0.1/manifests/bazs.test.baz.crd.yaml new file mode 100644 index 000000000..757fde072 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.1/manifests/bazs.test.baz.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bazs.test.baz +spec: + group: test.baz + names: + kind: Baz + plural: bazs + versions: + - name: v1 diff --git a/alpha/action/testdata/baz-bundle-v1.0.1/metadata/annotations.yaml b/alpha/action/testdata/baz-bundle-v1.0.1/metadata/annotations.yaml new file mode 100644 index 000000000..23fcd1406 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.0.1/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: baz + operators.operatorframework.io.bundle.channels.v1: stable + operators.operatorframework.io.bundle.channel.default.v1: stable diff --git a/alpha/action/testdata/baz-bundle-v1.1.0/bundle.Dockerfile b/alpha/action/testdata/baz-bundle-v1.1.0/bundle.Dockerfile new file mode 100644 index 000000000..5351aff0b --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.1.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=baz +LABEL operators.operatorframework.io.bundle.channels.v1=stable + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/baz-bundle-v1.1.0/manifests/baz.csv.yaml b/alpha/action/testdata/baz-bundle-v1.1.0/manifests/baz.csv.yaml new file mode 100644 index 000000000..e13b42514 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.1.0/manifests/baz.csv.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: baz.v1.1.0 +spec: + customresourcedefinitions: + owned: + - group: test.baz + version: v1 + kind: Baz + name: bazs.test.baz + version: 1.1.0 + replaces: baz.v1.0.0 + relatedImages: + - name: operator + image: test.registry/baz-operator/baz:v1.1.0 diff --git a/alpha/action/testdata/baz-bundle-v1.1.0/manifests/bazs.test.baz.crd.yaml b/alpha/action/testdata/baz-bundle-v1.1.0/manifests/bazs.test.baz.crd.yaml new file mode 100644 index 000000000..757fde072 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.1.0/manifests/bazs.test.baz.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: bazs.test.baz +spec: + group: test.baz + names: + kind: Baz + plural: bazs + versions: + - name: v1 diff --git a/alpha/action/testdata/baz-bundle-v1.1.0/metadata/annotations.yaml b/alpha/action/testdata/baz-bundle-v1.1.0/metadata/annotations.yaml new file mode 100644 index 000000000..23fcd1406 --- /dev/null +++ b/alpha/action/testdata/baz-bundle-v1.1.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: baz + operators.operatorframework.io.bundle.channels.v1: stable + operators.operatorframework.io.bundle.channel.default.v1: stable diff --git a/alpha/action/testdata/foo-bundle-v0.1.0/bundle.Dockerfile b/alpha/action/testdata/foo-bundle-v0.1.0/bundle.Dockerfile new file mode 100644 index 000000000..df0043928 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.1.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=foo +LABEL operators.operatorframework.io.bundle.channels.v1=beta + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml b/alpha/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml new file mode 100644 index 000000000..189b6849e --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: foo.v0.1.0 + annotations: + olm.skipRange: <0.1.0 +spec: + displayName: "Foo Operator" + customresourcedefinitions: + owned: + - group: test.foo + version: v1 + kind: Foo + name: foos.test.foo + version: 0.1.0 + relatedImages: + - name: operator + image: test.registry/foo-operator/foo:v0.1.0 diff --git a/alpha/action/testdata/foo-bundle-v0.1.0/manifests/foos.test.foo.crd.yaml b/alpha/action/testdata/foo-bundle-v0.1.0/manifests/foos.test.foo.crd.yaml new file mode 100644 index 000000000..39b762b50 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.1.0/manifests/foos.test.foo.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: foos.test.foo +spec: + group: test.foo + names: + kind: Foo + plural: foos + versions: + - name: v1 diff --git a/alpha/action/testdata/foo-bundle-v0.1.0/metadata/annotations.yaml b/alpha/action/testdata/foo-bundle-v0.1.0/metadata/annotations.yaml new file mode 100644 index 000000000..34187f125 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.1.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: foo + operators.operatorframework.io.bundle.channels.v1: beta + operators.operatorframework.io.bundle.channel.default.v1: beta diff --git a/alpha/action/testdata/foo-bundle-v0.1.0/metadata/dependencies.yaml b/alpha/action/testdata/foo-bundle-v0.1.0/metadata/dependencies.yaml new file mode 100644 index 000000000..e5d50aefd --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.1.0/metadata/dependencies.yaml @@ -0,0 +1,11 @@ +--- +dependencies: + - type: olm.package + value: + packageName: bar + version: <0.1.0 + - type: olm.gvk + value: + group: "test.bar" + version: "v1alpha1" + kind: "Bar" diff --git a/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/bundle.Dockerfile b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/bundle.Dockerfile new file mode 100644 index 000000000..df0043928 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=foo +LABEL operators.operatorframework.io.bundle.channels.v1=beta + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foo.v0.2.0.csv.yaml b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foo.v0.2.0.csv.yaml new file mode 100644 index 000000000..82aeecdaf --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foo.v0.2.0.csv.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: foo.v0.2.0 + annotations: + olm.skipRange: <0.2.0 +spec: + displayName: "Foo Operator" + customresourcedefinitions: + owned: + - group: test.foo + version: v1 + kind: Foo + name: foos.test.foo + version: 0.2.0 + replaces: foo.v0.1.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 + install: + strategy: deployment + spec: + deployments: + - name: foo-operator + spec: + template: + spec: + initContainers: + - image: test.registry/foo-operator/foo-init:v0.2.0 + containers: + - image: test.registry/foo-operator/foo:v0.2.0 + - name: foo-operator-2 + spec: + template: + spec: + initContainers: + - image: test.registry/foo-operator/foo-init-2:v0.2.0 + containers: + - image: test.registry/foo-operator/foo-2:v0.2.0 diff --git a/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foos.test.foo.crd.yaml b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foos.test.foo.crd.yaml new file mode 100644 index 000000000..39b762b50 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/manifests/foos.test.foo.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: foos.test.foo +spec: + group: test.foo + names: + kind: Foo + plural: foos + versions: + - name: v1 diff --git a/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/annotations.yaml b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/annotations.yaml new file mode 100644 index 000000000..dc4cc05f6 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: foo + operators.operatorframework.io.bundle.channels.v1: beta,stable + operators.operatorframework.io.bundle.channel.default.v1: beta diff --git a/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/dependencies.yaml b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/dependencies.yaml new file mode 100644 index 000000000..e5d50aefd --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0-no-csv-related-images/metadata/dependencies.yaml @@ -0,0 +1,11 @@ +--- +dependencies: + - type: olm.package + value: + packageName: bar + version: <0.1.0 + - type: olm.gvk + value: + group: "test.bar" + version: "v1alpha1" + kind: "Bar" diff --git a/alpha/action/testdata/foo-bundle-v0.2.0/bundle.Dockerfile b/alpha/action/testdata/foo-bundle-v0.2.0/bundle.Dockerfile new file mode 100644 index 000000000..df0043928 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=foo +LABEL operators.operatorframework.io.bundle.channels.v1=beta + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml b/alpha/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml new file mode 100644 index 000000000..823f91c0f --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0/manifests/foo.v0.2.0.csv.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: foo.v0.2.0 + annotations: + olm.skipRange: <0.2.0 +spec: + displayName: "Foo Operator" + customresourcedefinitions: + owned: + - group: test.foo + version: v1 + kind: Foo + name: foos.test.foo + version: 0.2.0 + replaces: foo.v0.1.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 + install: + strategy: deployment + spec: + deployments: + - name: foo-operator + spec: + template: + spec: + initContainers: + - image: test.registry/foo-operator/foo-init:v0.2.0 + containers: + - image: test.registry/foo-operator/foo:v0.2.0 + - name: foo-operator-2 + spec: + template: + spec: + initContainers: + - image: test.registry/foo-operator/foo-init-2:v0.2.0 + containers: + - image: test.registry/foo-operator/foo-2:v0.2.0 + relatedImages: + - name: operator + image: test.registry/foo-operator/foo:v0.2.0 + - name: other + image: test.registry/foo-operator/foo-other:v0.2.0 diff --git a/alpha/action/testdata/foo-bundle-v0.2.0/manifests/foos.test.foo.crd.yaml b/alpha/action/testdata/foo-bundle-v0.2.0/manifests/foos.test.foo.crd.yaml new file mode 100644 index 000000000..39b762b50 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0/manifests/foos.test.foo.crd.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: foos.test.foo +spec: + group: test.foo + names: + kind: Foo + plural: foos + versions: + - name: v1 diff --git a/alpha/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml b/alpha/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml new file mode 100644 index 000000000..dc4cc05f6 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: foo + operators.operatorframework.io.bundle.channels.v1: beta,stable + operators.operatorframework.io.bundle.channel.default.v1: beta diff --git a/alpha/action/testdata/foo-bundle-v0.2.0/metadata/dependencies.yaml b/alpha/action/testdata/foo-bundle-v0.2.0/metadata/dependencies.yaml new file mode 100644 index 000000000..e5d50aefd --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.2.0/metadata/dependencies.yaml @@ -0,0 +1,11 @@ +--- +dependencies: + - type: olm.package + value: + packageName: bar + version: <0.1.0 + - type: olm.gvk + value: + group: "test.bar" + version: "v1alpha1" + kind: "Bar" diff --git a/alpha/action/testdata/foo-bundle-v0.3.0/bundle.Dockerfile b/alpha/action/testdata/foo-bundle-v0.3.0/bundle.Dockerfile new file mode 100644 index 000000000..df0043928 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.0/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=foo +LABEL operators.operatorframework.io.bundle.channels.v1=beta + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/foo-bundle-v0.3.0/manifests/foo.csv.yaml b/alpha/action/testdata/foo-bundle-v0.3.0/manifests/foo.csv.yaml new file mode 100644 index 000000000..589731b07 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.0/manifests/foo.csv.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: foo.v0.3.0 +spec: + customresourcedefinitions: + owned: + - group: test.foo + version: v1 + kind: Foo + name: foos.test.foo + - group: test.foo + version: v2 + kind: Foo + name: foos.test.foo + version: 0.3.0 + replaces: foo.v0.2.0 + relatedImages: + - name: operator + image: test.registry/foo-operator/foo:v0.3.0 diff --git a/alpha/action/testdata/foo-bundle-v0.3.0/manifests/foos.test.foo.crd.yaml b/alpha/action/testdata/foo-bundle-v0.3.0/manifests/foos.test.foo.crd.yaml new file mode 100644 index 000000000..6bf85a3ca --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.0/manifests/foos.test.foo.crd.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: foos.test.foo +spec: + group: test.foo + names: + kind: Foo + plural: foos + versions: + - name: v1 + served: true + storage: false + - name: v2 + served: true + storage: true diff --git a/alpha/action/testdata/foo-bundle-v0.3.0/metadata/annotations.yaml b/alpha/action/testdata/foo-bundle-v0.3.0/metadata/annotations.yaml new file mode 100644 index 000000000..0cec7ef3e --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.0/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: foo + operators.operatorframework.io.bundle.channels.v1: beta + operators.operatorframework.io.bundle.channel.default.v1: beta \ No newline at end of file diff --git a/alpha/action/testdata/foo-bundle-v0.3.0/metadata/dependencies.yaml b/alpha/action/testdata/foo-bundle-v0.3.0/metadata/dependencies.yaml new file mode 100644 index 000000000..2315b30f6 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.0/metadata/dependencies.yaml @@ -0,0 +1,11 @@ +--- +dependencies: + - type: olm.package + value: + packageName: bar + version: <0.2.0 + - type: olm.gvk + value: + group: "test.bar" + version: "v1alpha1" + kind: "Bar" diff --git a/alpha/action/testdata/foo-bundle-v0.3.1/bundle.Dockerfile b/alpha/action/testdata/foo-bundle-v0.3.1/bundle.Dockerfile new file mode 100644 index 000000000..df0043928 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.1/bundle.Dockerfile @@ -0,0 +1,12 @@ +FROM scratch + +# Core bundle labels. +LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 +LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ +LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ +LABEL operators.operatorframework.io.bundle.package.v1=foo +LABEL operators.operatorframework.io.bundle.channels.v1=beta + +# Copy files to locations specified by labels. +COPY manifests /manifests/ +COPY metadata /metadata/ diff --git a/alpha/action/testdata/foo-bundle-v0.3.1/manifests/foo.csv.yaml b/alpha/action/testdata/foo-bundle-v0.3.1/manifests/foo.csv.yaml new file mode 100644 index 000000000..ab0f11aaf --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.1/manifests/foo.csv.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: foo.v0.3.1 +spec: + customresourcedefinitions: + owned: + - group: test.foo + version: v1 + kind: Foo + name: foos.test.foo + - group: test.foo + version: v2 + kind: Foo + name: foos.test.foo + version: 0.3.1 + replaces: foo.v0.2.0 + skips: + - foo.v0.3.0 + relatedImages: + - name: operator + image: test.registry/foo-operator/foo:v0.3.1 diff --git a/alpha/action/testdata/foo-bundle-v0.3.1/manifests/foos.test.foo.crd.yaml b/alpha/action/testdata/foo-bundle-v0.3.1/manifests/foos.test.foo.crd.yaml new file mode 100644 index 000000000..6bf85a3ca --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.1/manifests/foos.test.foo.crd.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: foos.test.foo +spec: + group: test.foo + names: + kind: Foo + plural: foos + versions: + - name: v1 + served: true + storage: false + - name: v2 + served: true + storage: true diff --git a/alpha/action/testdata/foo-bundle-v0.3.1/metadata/annotations.yaml b/alpha/action/testdata/foo-bundle-v0.3.1/metadata/annotations.yaml new file mode 100644 index 000000000..0cec7ef3e --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.1/metadata/annotations.yaml @@ -0,0 +1,4 @@ +annotations: + operators.operatorframework.io.bundle.package.v1: foo + operators.operatorframework.io.bundle.channels.v1: beta + operators.operatorframework.io.bundle.channel.default.v1: beta \ No newline at end of file diff --git a/alpha/action/testdata/foo-bundle-v0.3.1/metadata/dependencies.yaml b/alpha/action/testdata/foo-bundle-v0.3.1/metadata/dependencies.yaml new file mode 100644 index 000000000..2315b30f6 --- /dev/null +++ b/alpha/action/testdata/foo-bundle-v0.3.1/metadata/dependencies.yaml @@ -0,0 +1,11 @@ +--- +dependencies: + - type: olm.package + value: + packageName: bar + version: <0.2.0 + - type: olm.gvk + value: + group: "test.bar" + version: "v1alpha1" + kind: "Bar" diff --git a/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml b/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml new file mode 100644 index 000000000..933b108d2 --- /dev/null +++ b/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml @@ -0,0 +1,111 @@ +--- +schema: olm.package +name: foo +defaultChannel: beta +properties: + - type: owner + value: + group: abc.com + name: admin +--- +schema: olm.channel +package: foo +name: beta +entries: + - name: foo.v0.1.0 + skipRange: <0.1.0 + - name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +properties: + - type: user + value: + group: xyz.com + name: account +--- +schema: olm.channel +package: foo +name: stable +entries: + - name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +--- +schema: olm.bundle +package: foo +name: foo.v0.1.0 +image: test.registry/foo-operator/foo-bundle:v0.1.0 +properties: + - type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 + - type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 + - type: olm.package + value: + packageName: foo + version: 0.1.0 + - type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/foo-operator/foo:v0.1.0 + name: operator + - image: test.registry/foo-operator/foo-bundle:v0.1.0 +--- +schema: olm.bundle +package: foo +name: foo.v0.2.0 +image: test.registry/foo-operator/foo-bundle:v0.2.0 +properties: + - type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 + - type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 + - type: olm.package + value: + packageName: foo + version: 0.2.0 + - type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwiaW5zdGFsbCI6eyJzcGVjIjp7ImRlcGxveW1lbnRzIjpbeyJuYW1lIjoiZm9vLW9wZXJhdG9yIiwic3BlYyI6eyJ0ZW1wbGF0ZSI6eyJzcGVjIjp7ImNvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQ6djAuMi4wIn1dfX19fSx7Im5hbWUiOiJmb28tb3BlcmF0b3ItMiIsInNwZWMiOnsidGVtcGxhdGUiOnsic3BlYyI6eyJjb250YWluZXJzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvby0yOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQtMjp2MC4yLjAifV19fX19XX0sInN0cmF0ZWd5IjoiZGVwbG95bWVudCJ9LCJyZWxhdGVkSW1hZ2VzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvbzp2MC4yLjAiLCJuYW1lIjoib3BlcmF0b3IifSx7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLW90aGVyOnYwLjIuMCIsIm5hbWUiOiJvdGhlciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/foo-operator/foo-2:v0.2.0 + - image: test.registry/foo-operator/foo-init-2:v0.2.0 + - image: test.registry/foo-operator/foo-init:v0.2.0 + - image: test.registry/foo-operator/foo-bundle:v0.2.0 + - image: test.registry/foo-operator/foo-other:v0.2.0 + name: other + - image: test.registry/foo-operator/foo:v0.2.0 + name: operator diff --git a/alpha/action/testdata/index-declcfgs/exp-headsonly/index.yaml b/alpha/action/testdata/index-declcfgs/exp-headsonly/index.yaml new file mode 100644 index 000000000..4b8fc1045 --- /dev/null +++ b/alpha/action/testdata/index-declcfgs/exp-headsonly/index.yaml @@ -0,0 +1,193 @@ +--- +defaultChannel: stable +name: bar +schema: olm.package +--- +name: alpha +package: bar +schema: olm.channel +entries: + - name: bar.v0.1.0 + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.0 + - name: bar.v1.0.0 + replaces: bar.v0.2.0 +--- +name: stable +package: bar +schema: olm.channel +entries: + - name: bar.v1.0.0 +--- +# Added because foo.v0.3.1 depends on bar <0.2.0 +image: test.registry/bar-operator/bar-bundle:v0.1.0 +name: bar.v0.1.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.1.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.1.0 + name: operator +schema: olm.bundle +--- +# Added because foo.v0.3.1 depends on Bar, test.bar/v1alpha1. +# Note that dependency selection cannot decide between bar 0.1.0 +# and 0.2.0, as this is resolver territory. +image: test.registry/bar-operator/bar-bundle:v0.2.0 +name: bar.v0.2.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.2.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.2.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v1.0.0 +name: bar.v1.0.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYxIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn0seyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4yLjAiLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 1.0.0 +relatedImages: +- image: test.registry/bar-operator/bar:v1.0.0 + name: operator +schema: olm.bundle +--- +defaultChannel: stable +name: baz +schema: olm.package +--- +name: stable +package: baz +schema: olm.channel +entries: + - name: baz.v1.1.0 + replaces: baz.v1.0.0 + skips: + - baz.v1.0.1 +--- +image: test.registry/baz-operator/baz-bundle:v1.1.0 +name: baz.v1.1.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhei52MS4wLjAiLCJ2ZXJzaW9uIjoiMS4xLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.1.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.1.0 + name: operator +schema: olm.bundle +--- +defaultChannel: beta +name: foo +schema: olm.package +--- +name: beta +package: foo +schema: olm.channel +entries: + - name: foo.v0.3.1 + replaces: foo.v0.2.0 + skips: + - foo.v0.3.0 +--- +image: test.registry/foo-operator/foo-bundle:v0.3.1 +name: foo.v0.3.1 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjEifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4xIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJza2lwcyI6WyJmb28udjAuMy4wIl0sInZlcnNpb24iOiIwLjMuMSJ9fQ== +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.1 +- type: olm.package.required + value: + packageName: bar + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.1 + name: operator +schema: olm.bundle diff --git a/alpha/action/testdata/index-declcfgs/exp-include-channel/index.yaml b/alpha/action/testdata/index-declcfgs/exp-include-channel/index.yaml new file mode 100644 index 000000000..f49e7ae20 --- /dev/null +++ b/alpha/action/testdata/index-declcfgs/exp-include-channel/index.yaml @@ -0,0 +1,248 @@ +--- +defaultChannel: stable +name: bar +schema: olm.package +--- +name: alpha +package: bar +schema: olm.channel +entries: + - name: bar.v0.1.0 + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.0 + - name: bar.v1.0.0 + replaces: bar.v0.2.0 +--- +name: stable +package: bar +schema: olm.channel +entries: + - name: bar.v1.0.0 +--- +# Added because foo.v0.3.1 depends on bar <0.2.0 +image: test.registry/bar-operator/bar-bundle:v0.1.0 +name: bar.v0.1.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.1.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.1.0 + name: operator +schema: olm.bundle +--- +# Added because foo.v0.3.1 depends on Bar, test.bar/v1alpha1. +# Note that dependency selection cannot decide between bar 0.1.0 +# and 0.2.0, as this is resolver territory. +image: test.registry/bar-operator/bar-bundle:v0.2.0 +name: bar.v0.2.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.2.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.2.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v1.0.0 +name: bar.v1.0.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYxIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn0seyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4yLjAiLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 1.0.0 +relatedImages: +- image: test.registry/bar-operator/bar:v1.0.0 + name: operator +schema: olm.bundle +--- +defaultChannel: stable +name: baz +schema: olm.package +--- +schema: olm.channel +package: baz +name: stable +entries: +- name: baz.v1.0.0 + skipRange: <1.0.0 +- name: baz.v1.0.1 + replaces: baz.v1.0.0 + skipRange: <1.0.0 + skips: + - baz.v1.0.0 +- name: baz.v1.1.0 + replaces: baz.v1.0.0 + skips: + - baz.v1.0.1 +--- +image: test.registry/baz-operator/baz-bundle:v1.0.0 +name: baz.v1.0.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.0 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.0.1 +name: baz.v1.0.1 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzEuMC4xIn0sIm5hbWUiOiJiYXoudjEuMC4xIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJheiIsImtpbmQiOiJCYXoiLCJuYW1lIjoiYmF6cy50ZXN0LmJheiIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXotb3BlcmF0b3IvYmF6OnYxLjAuMSIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmF6LnYxLjAuMCJdLCJ2ZXJzaW9uIjoiMS4wLjEifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.1 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.1 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.1.0 +name: baz.v1.1.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhei52MS4wLjAiLCJ2ZXJzaW9uIjoiMS4xLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.1.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.1.0 + name: operator +schema: olm.bundle +--- +defaultChannel: beta +name: foo +schema: olm.package +--- +name: beta +package: foo +schema: olm.channel +entries: + - name: foo.v0.3.1 + replaces: foo.v0.2.0 + skips: + - foo.v0.3.0 +--- +image: test.registry/foo-operator/foo-bundle:v0.3.1 +name: foo.v0.3.1 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjEifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4xIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJza2lwcyI6WyJmb28udjAuMy4wIl0sInZlcnNpb24iOiIwLjMuMSJ9fQ== +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.1 +- type: olm.package.required + value: + packageName: bar + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.1 + name: operator +schema: olm.bundle diff --git a/alpha/action/testdata/index-declcfgs/exp-include-pkg/index.yaml b/alpha/action/testdata/index-declcfgs/exp-include-pkg/index.yaml new file mode 100644 index 000000000..f49e7ae20 --- /dev/null +++ b/alpha/action/testdata/index-declcfgs/exp-include-pkg/index.yaml @@ -0,0 +1,248 @@ +--- +defaultChannel: stable +name: bar +schema: olm.package +--- +name: alpha +package: bar +schema: olm.channel +entries: + - name: bar.v0.1.0 + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.0 + - name: bar.v1.0.0 + replaces: bar.v0.2.0 +--- +name: stable +package: bar +schema: olm.channel +entries: + - name: bar.v1.0.0 +--- +# Added because foo.v0.3.1 depends on bar <0.2.0 +image: test.registry/bar-operator/bar-bundle:v0.1.0 +name: bar.v0.1.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.1.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.1.0 + name: operator +schema: olm.bundle +--- +# Added because foo.v0.3.1 depends on Bar, test.bar/v1alpha1. +# Note that dependency selection cannot decide between bar 0.1.0 +# and 0.2.0, as this is resolver territory. +image: test.registry/bar-operator/bar-bundle:v0.2.0 +name: bar.v0.2.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.2.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.2.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v1.0.0 +name: bar.v1.0.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYxIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn0seyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4yLjAiLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 1.0.0 +relatedImages: +- image: test.registry/bar-operator/bar:v1.0.0 + name: operator +schema: olm.bundle +--- +defaultChannel: stable +name: baz +schema: olm.package +--- +schema: olm.channel +package: baz +name: stable +entries: +- name: baz.v1.0.0 + skipRange: <1.0.0 +- name: baz.v1.0.1 + replaces: baz.v1.0.0 + skipRange: <1.0.0 + skips: + - baz.v1.0.0 +- name: baz.v1.1.0 + replaces: baz.v1.0.0 + skips: + - baz.v1.0.1 +--- +image: test.registry/baz-operator/baz-bundle:v1.0.0 +name: baz.v1.0.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.0 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.0.1 +name: baz.v1.0.1 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzEuMC4xIn0sIm5hbWUiOiJiYXoudjEuMC4xIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJheiIsImtpbmQiOiJCYXoiLCJuYW1lIjoiYmF6cy50ZXN0LmJheiIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXotb3BlcmF0b3IvYmF6OnYxLjAuMSIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmF6LnYxLjAuMCJdLCJ2ZXJzaW9uIjoiMS4wLjEifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.1 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.1 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.1.0 +name: baz.v1.1.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhei52MS4wLjAiLCJ2ZXJzaW9uIjoiMS4xLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.1.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.1.0 + name: operator +schema: olm.bundle +--- +defaultChannel: beta +name: foo +schema: olm.package +--- +name: beta +package: foo +schema: olm.channel +entries: + - name: foo.v0.3.1 + replaces: foo.v0.2.0 + skips: + - foo.v0.3.0 +--- +image: test.registry/foo-operator/foo-bundle:v0.3.1 +name: foo.v0.3.1 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjEifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4xIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJza2lwcyI6WyJmb28udjAuMy4wIl0sInZlcnNpb24iOiIwLjMuMSJ9fQ== +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.1 +- type: olm.package.required + value: + packageName: bar + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.1 + name: operator +schema: olm.bundle diff --git a/alpha/action/testdata/index-declcfgs/exp-latest/index.yaml b/alpha/action/testdata/index-declcfgs/exp-latest/index.yaml new file mode 100644 index 000000000..8911e9a15 --- /dev/null +++ b/alpha/action/testdata/index-declcfgs/exp-latest/index.yaml @@ -0,0 +1,134 @@ +--- +defaultChannel: stable +name: bar +schema: olm.package +--- +name: alpha +package: bar +schema: olm.channel +entries: + - name: bar.v1.0.0 + replaces: bar.v0.2.0 +--- +name: stable +package: bar +schema: olm.channel +entries: + - name: bar.v1.0.0 +--- +image: test.registry/bar-operator/bar-bundle:v1.0.0 +name: bar.v1.0.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYxIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn0seyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4yLjAiLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 1.0.0 +relatedImages: +- image: test.registry/bar-operator/bar:v1.0.0 + name: operator +schema: olm.bundle +--- +defaultChannel: stable +name: baz +schema: olm.package +--- +name: stable +package: baz +schema: olm.channel +entries: + - name: baz.v1.1.0 + replaces: baz.v1.0.0 + skips: + - baz.v1.0.1 +--- +image: test.registry/baz-operator/baz-bundle:v1.1.0 +name: baz.v1.1.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhei52MS4wLjAiLCJ2ZXJzaW9uIjoiMS4xLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.1.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.1.0 + name: operator +schema: olm.bundle +--- +defaultChannel: beta +name: foo +schema: olm.package +--- +name: beta +package: foo +schema: olm.channel +entries: + - name: foo.v0.3.1 + replaces: foo.v0.2.0 + skips: + - foo.v0.3.0 +--- +image: test.registry/foo-operator/foo-bundle:v0.3.1 +name: foo.v0.3.1 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjEifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4xIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJza2lwcyI6WyJmb28udjAuMy4wIl0sInZlcnNpb24iOiIwLjMuMSJ9fQ== +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.1 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.1 + name: operator +schema: olm.bundle diff --git a/alpha/action/testdata/index-declcfgs/latest/index.yaml b/alpha/action/testdata/index-declcfgs/latest/index.yaml new file mode 100644 index 000000000..4b06fbacf --- /dev/null +++ b/alpha/action/testdata/index-declcfgs/latest/index.yaml @@ -0,0 +1,357 @@ +--- +defaultChannel: stable +name: bar +schema: olm.package +--- +name: alpha +package: bar +schema: olm.channel +entries: + - name: bar.v0.1.0 + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.0 + - name: bar.v1.0.0 + replaces: bar.v0.2.0 +--- +name: stable +package: bar +schema: olm.channel +entries: + - name: bar.v1.0.0 +--- +image: test.registry/bar-operator/bar-bundle:v0.1.0 +name: bar.v0.1.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.1.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v0.2.0 +name: bar.v0.2.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.2.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.2.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v1.0.0 +name: bar.v1.0.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYxIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn0seyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4yLjAiLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 1.0.0 +relatedImages: +- image: test.registry/bar-operator/bar:v1.0.0 + name: operator +schema: olm.bundle +--- +defaultChannel: stable +name: baz +schema: olm.package +--- +schema: olm.channel +package: baz +name: stable +entries: + - name: baz.v1.0.0 + skipRange: <1.0.0 + - name: baz.v1.0.1 + replaces: baz.v1.0.0 + skipRange: <1.0.0 + skips: + - baz.v1.0.0 + - name: baz.v1.1.0 + replaces: baz.v1.0.0 + skips: + - baz.v1.0.1 +--- +image: test.registry/baz-operator/baz-bundle:v1.0.0 +name: baz.v1.0.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.0 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.0.1 +name: baz.v1.0.1 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzEuMC4xIn0sIm5hbWUiOiJiYXoudjEuMC4xIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJheiIsImtpbmQiOiJCYXoiLCJuYW1lIjoiYmF6cy50ZXN0LmJheiIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXotb3BlcmF0b3IvYmF6OnYxLjAuMSIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmF6LnYxLjAuMCJdLCJ2ZXJzaW9uIjoiMS4wLjEifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.1 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.1 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.1.0 +name: baz.v1.1.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhei52MS4wLjAiLCJ2ZXJzaW9uIjoiMS4xLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.1.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.1.0 + name: operator +schema: olm.bundle +--- +defaultChannel: beta +name: foo +schema: olm.package +--- +schema: olm.channel +package: foo +name: beta +entries: + - name: foo.v0.1.0 + skipRange: <0.1.0 + - name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 + - name: foo.v0.3.0 + replaces: foo.v0.2.0 + - name: foo.v0.3.1 + replaces: foo.v0.2.0 + skips: + - foo.v0.3.0 +--- +image: test.registry/foo-operator/foo-bundle:v0.1.0 +name: foo.v0.1.0 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjEuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwidmVyc2lvbiI6IjAuMS4wIn19 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.1.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.2.0 +name: foo.v0.2.0 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.2.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.2.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.3.0 +name: foo.v0.3.0 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJ2ZXJzaW9uIjoiMC4zLjAifX0= +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.3.1 +name: foo.v0.3.1 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjEifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4xIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJza2lwcyI6WyJmb28udjAuMy4wIl0sInZlcnNpb24iOiIwLjMuMSJ9fQ== +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.1 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.1 + name: operator +schema: olm.bundle diff --git a/alpha/action/testdata/index-declcfgs/old/index.yaml b/alpha/action/testdata/index-declcfgs/old/index.yaml new file mode 100644 index 000000000..f3cc41dfd --- /dev/null +++ b/alpha/action/testdata/index-declcfgs/old/index.yaml @@ -0,0 +1,250 @@ +--- +defaultChannel: alpha +name: bar +schema: olm.package +--- +schema: olm.channel +package: bar +name: alpha +entries: + - name: bar.v0.1.0 + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.0 +--- +image: test.registry/bar-operator/bar-bundle:v0.1.0 +name: bar.v0.1.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.1.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/bar-operator/bar-bundle:v0.2.0 +name: bar.v0.2.0 +package: bar +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= +- type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: bar + version: 0.2.0 +relatedImages: +- image: test.registry/bar-operator/bar:v0.2.0 + name: operator +schema: olm.bundle +--- +defaultChannel: stable +name: baz +schema: olm.package +--- +schema: olm.channel +package: baz +name: stable +entries: + - name: baz.v1.0.0 + skipRange: <1.0.0 + - name: baz.v1.0.1 + replaces: baz.v1.0.0 + skipRange: <1.0.0 + skips: + - baz.v1.0.0 +--- +image: test.registry/baz-operator/baz-bundle:v1.0.0 +name: baz.v1.0.0 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhei52MS4wLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmF6Iiwia2luZCI6IkJheiIsIm5hbWUiOiJiYXpzLnRlc3QuYmF6IiwidmVyc2lvbiI6InYxIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhei1vcGVyYXRvci9iYXo6djEuMC4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMS4wLjAifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.0 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.0 + name: operator +schema: olm.bundle +--- +image: test.registry/baz-operator/baz-bundle:v1.0.1 +name: baz.v1.0.1 +package: baz +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhenMudGVzdC5iYXoifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmF6IiwibmFtZXMiOnsia2luZCI6IkJheiIsInBsdXJhbCI6ImJhenMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzEuMC4xIn0sIm5hbWUiOiJiYXoudjEuMC4xIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJheiIsImtpbmQiOiJCYXoiLCJuYW1lIjoiYmF6cy50ZXN0LmJheiIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXotb3BlcmF0b3IvYmF6OnYxLjAuMSIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmF6LnYxLjAuMCJdLCJ2ZXJzaW9uIjoiMS4wLjEifX0= +- type: olm.gvk + value: + group: test.baz + kind: Baz + version: v1 +- type: olm.package + value: + packageName: baz + version: 1.0.1 +relatedImages: +- image: test.registry/baz-operator/baz:v1.0.1 + name: operator +schema: olm.bundle +--- +defaultChannel: beta +name: foo +schema: olm.package +--- +schema: olm.channel +package: foo +name: beta +entries: + - name: foo.v0.1.0 + skipRange: <0.1.0 + - name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 + - name: foo.v0.3.0 + replaces: foo.v0.2.0 +--- +image: test.registry/foo-operator/foo-bundle:v0.1.0 +name: foo.v0.1.0 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjEuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwidmVyc2lvbiI6IjAuMS4wIn19 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.1.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.1.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.2.0 +name: foo.v0.2.0 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.2.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.1.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.2.0 + name: operator +schema: olm.bundle +--- +image: test.registry/foo-operator/foo-bundle:v0.3.0 +name: foo.v0.3.0 +package: foo +properties: +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSIsInNlcnZlZCI6dHJ1ZSwic3RvcmFnZSI6ZmFsc2V9LHsibmFtZSI6InYyIiwic2VydmVkIjp0cnVlLCJzdG9yYWdlIjp0cnVlfV19fQ== +- type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvby52MC4zLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYxIn0seyJncm91cCI6InRlc3QuZm9vIiwia2luZCI6IkZvbyIsIm5hbWUiOiJmb29zLnRlc3QuZm9vIiwidmVyc2lvbiI6InYyIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMy4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4yLjAiLCJ2ZXJzaW9uIjoiMC4zLjAifX0= +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 +- type: olm.gvk + value: + group: test.foo + kind: Foo + version: v2 +- type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 +- type: olm.package + value: + packageName: foo + version: 0.3.0 +- type: olm.package.required + value: + packageName: bar + versionRange: <0.2.0 +relatedImages: +- image: test.registry/foo-operator/foo:v0.3.0 + name: operator +schema: olm.bundle diff --git a/alpha/action/testdata/list-index/bar/index.yaml b/alpha/action/testdata/list-index/bar/index.yaml new file mode 100644 index 000000000..37190ffb8 --- /dev/null +++ b/alpha/action/testdata/list-index/bar/index.yaml @@ -0,0 +1,96 @@ +--- +schema: olm.package +name: bar +defaultChannel: beta +--- +schema: olm.channel +package: bar +name: beta +entries: + - name: bar.v0.1.0 + skipRange: <0.1.0 + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.1 + - bar.v0.1.2 +--- +schema: olm.channel +package: bar +name: stable +entries: + - name: bar.v0.2.0 + replaces: bar.v0.1.0 + skipRange: <0.2.0 + skips: + - bar.v0.1.1 + - bar.v0.1.2 +--- +schema: olm.bundle +package: bar +name: bar.v0.1.0 +image: test.registry/bar-operator/bar-bundle:v0.1.0 +properties: + - type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 + - type: olm.gvk.required + value: + group: test.baz + kind: Baz + version: v1alpha1 + - type: olm.package + value: + packageName: bar + version: 0.1.0 + - type: olm.package.required + value: + packageName: baz + versionRange: v0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJiYXIudjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiQmFyIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/bar-operator/bar:v0.1.0 + name: operator + - image: test.registry/bar-operator/bar-bundle:v0.1.0 +--- +schema: olm.bundle +package: bar +name: bar.v0.2.0 +image: test.registry/bar-operator/bar-bundle:v0.2.0 +properties: + - type: olm.gvk + value: + group: test.bar + kind: Bar + version: v1 + - type: olm.gvk.required + value: + group: test.baz + kind: Baz + version: v1alpha1 + - type: olm.package + value: + packageName: bar + version: 0.2.0 + - type: olm.package.required + value: + packageName: baz + versionRange: v0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiQmFyIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMi4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImJhci52MC4xLjAiLCJza2lwcyI6WyJiYXIudjAuMS4xIiwiYmFyLnYwLjEuMiJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/bar-operator/bar:v0.2.0 + name: operator + - image: test.registry/bar-operator/bar-bundle:v0.2.0 diff --git a/alpha/action/testdata/list-index/foo/index.yaml b/alpha/action/testdata/list-index/foo/index.yaml new file mode 100644 index 000000000..41b7d22df --- /dev/null +++ b/alpha/action/testdata/list-index/foo/index.yaml @@ -0,0 +1,96 @@ +--- +schema: olm.package +name: foo +defaultChannel: beta +--- +schema: olm.channel +package: foo +name: beta +entries: + - name: foo.v0.1.0 + skipRange: <0.1.0 + - name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +--- +schema: olm.channel +package: foo +name: stable +entries: + - name: foo.v0.2.0 + replaces: foo.v0.1.0 + skipRange: <0.2.0 + skips: + - foo.v0.1.1 + - foo.v0.1.2 +--- +schema: olm.bundle +package: foo +name: foo.v0.1.0 +image: test.registry/foo-operator/foo-bundle:v0.1.0 +properties: + - type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 + - type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 + - type: olm.package + value: + packageName: foo + version: 0.1.0 + - type: olm.package.required + value: + packageName: bar + versionRange: v0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/foo-operator/foo:v0.1.0 + name: operator + - image: test.registry/foo-operator/foo-bundle:v0.1.0 +--- +schema: olm.bundle +package: foo +name: foo.v0.2.0 +image: test.registry/foo-operator/foo-bundle:v0.2.0 +properties: + - type: olm.gvk + value: + group: test.foo + kind: Foo + version: v1 + - type: olm.gvk.required + value: + group: test.bar + kind: Bar + version: v1alpha1 + - type: olm.package + value: + packageName: foo + version: 0.2.0 + - type: olm.package.required + value: + packageName: bar + versionRange: v0.1.0 + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMi4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJyZXBsYWNlcyI6ImZvby52MC4xLjAiLCJza2lwcyI6WyJmb28udjAuMS4xIiwiZm9vLnYwLjEuMiJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0= + - type: olm.bundle.object + value: + data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19 +relatedImages: + - image: test.registry/foo-operator/foo:v0.2.0 + name: operator + - image: test.registry/foo-operator/foo-bundle:v0.2.0 diff --git a/alpha/declcfg/declcfg.go b/alpha/declcfg/declcfg.go new file mode 100644 index 000000000..9e4f752ee --- /dev/null +++ b/alpha/declcfg/declcfg.go @@ -0,0 +1,208 @@ +package declcfg + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + + "golang.org/x/text/cases" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/operator-framework/operator-registry/alpha/property" + prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler" +) + +const ( + SchemaPackage = "olm.package" + SchemaChannel = "olm.channel" + SchemaBundle = "olm.bundle" + SchemaDeprecation = "olm.deprecations" +) + +type DeclarativeConfig struct { + Packages []Package + Channels []Channel + Bundles []Bundle + Deprecations []Deprecation + Others []Meta +} + +type Package struct { + Schema string `json:"schema"` + Name string `json:"name"` + DefaultChannel string `json:"defaultChannel"` + Icon *Icon `json:"icon,omitempty"` + Description string `json:"description,omitempty"` + Properties []property.Property `json:"properties,omitempty" hash:"set"` +} + +type Icon struct { + Data []byte `json:"base64data"` + MediaType string `json:"mediatype"` +} + +type Channel struct { + Schema string `json:"schema"` + Name string `json:"name"` + Package string `json:"package"` + Entries []ChannelEntry `json:"entries"` + Properties []property.Property `json:"properties,omitempty" hash:"set"` +} + +type ChannelEntry struct { + Name string `json:"name"` + Replaces string `json:"replaces,omitempty"` + Skips []string `json:"skips,omitempty"` + SkipRange string `json:"skipRange,omitempty"` +} + +// Bundle specifies all metadata and data of a bundle object. +// Top-level fields are the source of truth, i.e. not CSV values. +// +// Notes: +// - Any field slice type field or type containing a slice somewhere +// where two types/fields are equal if their contents are equal regardless +// of order must have a `hash:"set"` field tag for bundle comparison. +// - Any fields that have a `json:"-"` tag must be included in the equality +// evaluation in bundlesEqual(). +type Bundle struct { + Schema string `json:"schema"` + Name string `json:"name,omitempty"` + Package string `json:"package,omitempty"` + Image string `json:"image"` + Properties []property.Property `json:"properties,omitempty" hash:"set"` + RelatedImages []RelatedImage `json:"relatedImages,omitempty" hash:"set"` + + // These fields are present so that we can continue serving + // the GRPC API the way packageserver expects us to in a + // backwards-compatible way. These are populated from + // any `olm.bundle.object` properties. + // + // These fields will never be persisted in the bundle blob as + // first class fields. + CsvJSON string `json:"-"` + Objects []string `json:"-"` +} + +type RelatedImage struct { + Name string `json:"name"` + Image string `json:"image"` +} + +type Deprecation struct { + Schema string `json:"schema"` + Package string `json:"package"` + Entries []DeprecationEntry `json:"entries"` +} + +type DeprecationEntry struct { + Reference PackageScopedReference `json:"reference"` + Message string `json:"message"` +} + +type PackageScopedReference struct { + Schema string `json:"schema"` + Name string `json:"name,omitempty"` +} + +type Meta struct { + Schema string + Package string + Name string + + Blob json.RawMessage +} + +func (m Meta) MarshalJSON() ([]byte, error) { + return m.Blob, nil +} + +func (m *Meta) UnmarshalJSON(blob []byte) error { + blobMap := map[string]interface{}{} + if err := json.Unmarshal(blob, &blobMap); err != nil { + // TODO: unfortunately, there are libraries between here and the original caller + // that eat our error type and return a generic error, such that we lose the + // ability to errors.As to get this error on the other side. For now, just return + // a string error that includes the pretty printed message. + return errors.New(prettyunmarshaler.NewJSONUnmarshalError(blob, err).Pretty()) + } + + // TODO: this function ensures we do not break backwards compatibility with + // the documented examples of FBC templates, which use upper camel case + // for JSON field names. We need to decide if we want to continue supporting + // case insensitive JSON field names, or if we want to enforce a specific + // case-sensitive key value for each field. + if err := extractUniqueMetaKeys(blobMap, m); err != nil { + return err + } + + buf := bytes.Buffer{} + enc := json.NewEncoder(&buf) + enc.SetEscapeHTML(false) + if err := enc.Encode(blobMap); err != nil { + return err + } + m.Blob = buf.Bytes() + return nil +} + +// extractUniqueMetaKeys enables a case-insensitive key lookup for the schema, package, and name +// fields of the Meta struct. If the blobMap contains duplicate keys (that is, keys have the same folded value), +// an error is returned. +func extractUniqueMetaKeys(blobMap map[string]any, m *Meta) error { + keySets := map[string]sets.Set[string]{} + folder := cases.Fold() + for key := range blobMap { + foldKey := folder.String(key) + if _, ok := keySets[foldKey]; !ok { + keySets[foldKey] = sets.New[string]() + } + keySets[foldKey].Insert(key) + } + + dupErrs := []error{} + for foldedKey, keys := range keySets { + if len(keys) != 1 { + dupErrs = append(dupErrs, fmt.Errorf("duplicate keys for key %q: %v", foldedKey, sets.List(keys))) + } + } + if len(dupErrs) > 0 { + return utilerrors.NewAggregate(dupErrs) + } + + metaMap := map[string]*string{ + folder.String("schema"): &m.Schema, + folder.String("package"): &m.Package, + folder.String("name"): &m.Name, + } + + for foldedKey, ptr := range metaMap { + // if the folded key doesn't exist in the key set derived from the blobMap, that means + // the key doesn't exist in the blobMap, so we can skip it + if _, ok := keySets[foldedKey]; !ok { + continue + } + + // reset key to the unfolded key, which we know is the one that appears in the blobMap + key := keySets[foldedKey].UnsortedList()[0] + if _, ok := blobMap[key]; !ok { + continue + } + v, ok := blobMap[key].(string) + if !ok { + return fmt.Errorf("expected value for key %q to be a string, got %t: %v", key, blobMap[key], blobMap[key]) + } + *ptr = v + } + return nil +} + +func (destination *DeclarativeConfig) Merge(src *DeclarativeConfig) { + destination.Packages = append(destination.Packages, src.Packages...) + destination.Channels = append(destination.Channels, src.Channels...) + destination.Bundles = append(destination.Bundles, src.Bundles...) + destination.Others = append(destination.Others, src.Others...) + destination.Deprecations = append(destination.Deprecations, src.Deprecations...) +} diff --git a/alpha/declcfg/declcfg_to_model.go b/alpha/declcfg/declcfg_to_model.go new file mode 100644 index 000000000..342cab403 --- /dev/null +++ b/alpha/declcfg/declcfg_to_model.go @@ -0,0 +1,257 @@ +package declcfg + +import ( + "fmt" + + "github.com/blang/semver/v4" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" + + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) { + mpkgs := model.Model{} + defaultChannels := map[string]string{} + for _, p := range cfg.Packages { + if p.Name == "" { + return nil, fmt.Errorf("config contains package with no name") + } + + if _, ok := mpkgs[p.Name]; ok { + return nil, fmt.Errorf("duplicate package %q", p.Name) + } + + if errs := validation.IsDNS1123Label(p.Name); len(errs) > 0 { + return nil, fmt.Errorf("invalid package name %q: %v", p.Name, errs) + } + + mpkg := &model.Package{ + Name: p.Name, + Description: p.Description, + Channels: map[string]*model.Channel{}, + } + if p.Icon != nil { + mpkg.Icon = &model.Icon{ + Data: p.Icon.Data, + MediaType: p.Icon.MediaType, + } + } + defaultChannels[p.Name] = p.DefaultChannel + mpkgs[p.Name] = mpkg + } + + channelDefinedEntries := map[string]sets.Set[string]{} + for _, c := range cfg.Channels { + mpkg, ok := mpkgs[c.Package] + if !ok { + return nil, fmt.Errorf("unknown package %q for channel %q", c.Package, c.Name) + } + + if c.Name == "" { + return nil, fmt.Errorf("package %q contains channel with no name", c.Package) + } + + if _, ok := mpkg.Channels[c.Name]; ok { + return nil, fmt.Errorf("package %q has duplicate channel %q", c.Package, c.Name) + } + + mch := &model.Channel{ + Package: mpkg, + Name: c.Name, + Bundles: map[string]*model.Bundle{}, + // NOTICE: The field Properties of the type Channel is for internal use only. + // DO NOT use it for any public-facing functionalities. + // This API is in alpha stage and it is subject to change. + Properties: c.Properties, + } + + cde := sets.Set[string]{} + for _, entry := range c.Entries { + if _, ok := mch.Bundles[entry.Name]; ok { + return nil, fmt.Errorf("invalid package %q, channel %q: duplicate entry %q", c.Package, c.Name, entry.Name) + } + cde = cde.Insert(entry.Name) + mch.Bundles[entry.Name] = &model.Bundle{ + Package: mpkg, + Channel: mch, + Name: entry.Name, + Replaces: entry.Replaces, + Skips: entry.Skips, + SkipRange: entry.SkipRange, + } + } + channelDefinedEntries[c.Package] = cde + + mpkg.Channels[c.Name] = mch + + defaultChannelName := defaultChannels[c.Package] + if defaultChannelName == c.Name { + mpkg.DefaultChannel = mch + } + } + + // packageBundles tracks the set of bundle names for each package + // and is used to detect duplicate bundles. + packageBundles := map[string]sets.Set[string]{} + + for _, b := range cfg.Bundles { + if b.Package == "" { + return nil, fmt.Errorf("package name must be set for bundle %q", b.Name) + } + mpkg, ok := mpkgs[b.Package] + if !ok { + return nil, fmt.Errorf("unknown package %q for bundle %q", b.Package, b.Name) + } + + bundles, ok := packageBundles[b.Package] + if !ok { + bundles = sets.Set[string]{} + } + if bundles.Has(b.Name) { + return nil, fmt.Errorf("package %q has duplicate bundle %q", b.Package, b.Name) + } + bundles.Insert(b.Name) + packageBundles[b.Package] = bundles + + props, err := property.Parse(b.Properties) + if err != nil { + return nil, fmt.Errorf("parse properties for bundle %q: %v", b.Name, err) + } + + if len(props.Packages) != 1 { + return nil, fmt.Errorf("package %q bundle %q must have exactly 1 %q property, found %d", b.Package, b.Name, property.TypePackage, len(props.Packages)) + } + + if b.Package != props.Packages[0].PackageName { + return nil, fmt.Errorf("package %q does not match %q property %q", b.Package, property.TypePackage, props.Packages[0].PackageName) + } + + // Parse version from the package property. + rawVersion := props.Packages[0].Version + ver, err := semver.Parse(rawVersion) + if err != nil { + return nil, fmt.Errorf("error parsing bundle %q version %q: %v", b.Name, rawVersion, err) + } + + channelDefinedEntries[b.Package] = channelDefinedEntries[b.Package].Delete(b.Name) + found := false + for _, mch := range mpkg.Channels { + if mb, ok := mch.Bundles[b.Name]; ok { + found = true + mb.Image = b.Image + mb.Properties = b.Properties + mb.RelatedImages = relatedImagesToModelRelatedImages(b.RelatedImages) + mb.CsvJSON = b.CsvJSON + mb.Objects = b.Objects + mb.PropertiesP = props + mb.Version = ver + } + } + if !found { + return nil, fmt.Errorf("package %q, bundle %q not found in any channel entries", b.Package, b.Name) + } + } + + for pkg, entries := range channelDefinedEntries { + if entries.Len() > 0 { + return nil, fmt.Errorf("no olm.bundle blobs found in package %q for olm.channel entries %s", pkg, sets.List[string](entries)) + } + } + + for _, mpkg := range mpkgs { + defaultChannelName := defaultChannels[mpkg.Name] + if defaultChannelName != "" && mpkg.DefaultChannel == nil { + dch := &model.Channel{ + Package: mpkg, + Name: defaultChannelName, + Bundles: map[string]*model.Bundle{}, + } + mpkg.DefaultChannel = dch + mpkg.Channels[dch.Name] = dch + } + } + + // deprecationsByPackage tracks the set of package names + // and is used to detect duplicate packages. + deprecationsByPackage := sets.New[string]() + + for i, deprecation := range cfg.Deprecations { + // no need to validate schema, since it could not be unmarshaled if missing/invalid + + if deprecation.Package == "" { + return nil, fmt.Errorf("package name must be set for deprecation item %v", i) + } + + // must refer to package in this catalog + mpkg, ok := mpkgs[deprecation.Package] + if !ok { + return nil, fmt.Errorf("cannot apply deprecations to an unknown package %q", deprecation.Package) + } + + // must be unique per package + if deprecationsByPackage.Has(deprecation.Package) { + return nil, fmt.Errorf("expected a maximum of one deprecation per package: %q", deprecation.Package) + } + deprecationsByPackage.Insert(deprecation.Package) + + references := sets.New[PackageScopedReference]() + + for j, entry := range deprecation.Entries { + if entry.Reference.Schema == "" { + return nil, fmt.Errorf("schema must be set for deprecation entry [%v] for package %q", deprecation.Package, j) + } + + if references.Has(entry.Reference) { + return nil, fmt.Errorf("duplicate deprecation entry %#v for package %q", entry.Reference, deprecation.Package) + } + references.Insert(entry.Reference) + + switch entry.Reference.Schema { + case SchemaBundle: + if !packageBundles[deprecation.Package].Has(entry.Reference.Name) { + return nil, fmt.Errorf("cannot deprecate bundle %q for package %q: bundle not found", entry.Reference.Name, deprecation.Package) + } + for _, mch := range mpkg.Channels { + if mb, ok := mch.Bundles[entry.Reference.Name]; ok { + mb.Deprecation = &model.Deprecation{Message: entry.Message} + } + } + case SchemaChannel: + ch, ok := mpkg.Channels[entry.Reference.Name] + if !ok { + return nil, fmt.Errorf("cannot deprecate channel %q for package %q: channel not found", entry.Reference.Name, deprecation.Package) + } + ch.Deprecation = &model.Deprecation{Message: entry.Message} + + case SchemaPackage: + if entry.Reference.Name != "" { + return nil, fmt.Errorf("package name must be empty for deprecated package %q (specified %q)", deprecation.Package, entry.Reference.Name) + } + mpkg.Deprecation = &model.Deprecation{Message: entry.Message} + + default: + return nil, fmt.Errorf("cannot deprecate object %#v referenced by entry %v for package %q: object schema unknown", entry.Reference, j, deprecation.Package) + } + } + } + + if err := mpkgs.Validate(); err != nil { + return nil, err + } + mpkgs.Normalize() + return mpkgs, nil +} + +func relatedImagesToModelRelatedImages(in []RelatedImage) []model.RelatedImage { + // nolint:prealloc + var out []model.RelatedImage + for _, p := range in { + out = append(out, model.RelatedImage{ + Name: p.Name, + Image: p.Image, + }) + } + return out +} diff --git a/alpha/declcfg/declcfg_to_model_test.go b/alpha/declcfg/declcfg_to_model_test.go new file mode 100644 index 000000000..de8639c1b --- /dev/null +++ b/alpha/declcfg/declcfg_to_model_test.go @@ -0,0 +1,515 @@ +package declcfg + +import ( + "encoding/json" + "testing" + + "github.com/blang/semver/v4" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func TestConvertToModel(t *testing.T) { + type spec struct { + name string + cfg DeclarativeConfig + assertion require.ErrorAssertionFunc + } + + specs := []spec{ + { + name: "Error/PackageNoName", + assertion: hasError(`config contains package with no name`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("", "alpha", svgSmallCircle)}, + Bundles: []Bundle{{Name: "foo.v0.1.0"}}, + }, + }, + { + name: "Error/BundleMissingPackageName", + assertion: hasError(`package name must be set for bundle "foo.v0.1.0"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{{Name: "foo.v0.1.0"}}, + }, + }, + { + name: "Error/BundleUnknownPackage", + assertion: hasError(`unknown package "bar" for bundle "bar.v0.1.0"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("bar", "0.1.0")}, + }, + }, + { + name: "Error/BundleMissingChannel", + assertion: hasError(`package "foo", bundle "foo.v0.1.0" not found in any channel entries`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/BundleInvalidProperties", + assertion: hasError(`parse properties for bundle "foo.v0.1.0": parse property[2] of type "olm.foo": unexpected end of JSON input`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", func(b *Bundle) { + b.Properties = append(b.Properties, property.Property{ + Type: "olm.foo", + Value: json.RawMessage("{"), + }) + })}, + }, + }, + { + name: "Error/BundlePackageMismatch", + assertion: hasError(`package "foo" does not match "olm.package" property "foooperator"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", func(b *Bundle) { + b.Properties = []property.Property{ + property.MustBuildPackage("foooperator", "0.1.0"), + } + })}, + }, + }, + { + name: "Error/BundleInvalidVersion", + assertion: hasError(`error parsing bundle "foo.v0.1.0" version "0.1.0.1": Invalid character(s) found in patch number "0.1"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", func(b *Bundle) { + b.Properties = []property.Property{ + property.MustBuildPackage("foo", "0.1.0.1"), + } + })}, + }, + }, + { + name: "Error/BundleMissingVersion", + assertion: hasError(`error parsing bundle "foo.v" version "": Version string empty`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "", func(b *Bundle) {})}, + }, + }, + { + name: "Error/PackageMissingDefaultChannel", + assertion: hasError(`invalid index: +└── invalid package "foo": + └── default channel must be set`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "bar", ChannelEntry{Name: testBundleName("foo", "0.1.0")})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/PackageNonExistentDefaultChannel", + assertion: hasError(`invalid index: +└── invalid package "foo": + └── invalid channel "bar": + └── channel must contain at least one bundle`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "bar", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "bar")}, + }, + }, + { + name: "Error/BundleMissingPackageProperty", + assertion: hasError(`package "foo" bundle "foo.v0.1.0" must have exactly 1 "olm.package" property, found 0`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", withNoProperties())}, + }, + }, + { + name: "Error/BundleMultiplePackageProperty", + assertion: hasError(`package "foo" bundle "foo.v0.1.0" must have exactly 1 "olm.package" property, found 2`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", func(b *Bundle) { + b.Properties = []property.Property{ + property.MustBuildPackage("foo", "0.1.0"), + property.MustBuildPackage("foo", "0.1.0"), + } + })}, + }, + }, + { + name: "Success/BundleWithDataButMissingImage", + assertion: require.NoError, + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: testBundleName("foo", "0.1.0")})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0", withNoBundleImage())}, + }, + }, + { + name: "Error/ChannelEntryWithoutBundle", + assertion: hasError(`no olm.bundle blobs found in package "foo" for olm.channel entries [foo.v0.1.0]`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + }, + }, + { + name: "Error/BundleWithoutChannelEntry", + assertion: hasError(`package "foo", bundle "foo.v0.2.0" not found in any channel entries`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.2.0")}, + }, + }, + { + name: "Error/ChannelMissingName", + assertion: hasError(`package "foo" contains channel with no name`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.2.0")}, + }, + }, + { + name: "Error/ChannelMissingPackageName", + assertion: hasError(`unknown package "" for channel "alpha"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.2.0")}, + }, + }, + { + name: "Error/ChannelNonExistentPackage", + assertion: hasError(`unknown package "non-existent" for channel "alpha"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("non-existent", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/ChannelDuplicateEntry", + assertion: hasError(`invalid package "foo", channel "alpha": duplicate entry "foo.v0.1.0"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", + ChannelEntry{Name: "foo.v0.1.0"}, + ChannelEntry{Name: "foo.v0.1.0"}, + )}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/DuplicatePackage", + assertion: hasError(`duplicate package "foo"`), + cfg: DeclarativeConfig{ + Packages: []Package{ + newTestPackage("foo", "alpha", svgSmallCircle), + newTestPackage("foo", "alpha", svgSmallCircle), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/PackageBreaksRFC1123", + assertion: hasError(`invalid package name "foo.bar": [must not contain dots]`), + cfg: DeclarativeConfig{ + Packages: []Package{ + newTestPackage("foo.bar", "alpha", svgSmallCircle), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/DuplicateChannel", + assertion: hasError(`package "foo" has duplicate channel "alpha"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{ + newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"}), + newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"}), + }, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/DuplicateBundle", + assertion: hasError(`package "foo" has duplicate bundle "foo.v0.1.0"`), + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{ + newTestBundle("foo", "0.1.0"), + newTestBundle("foo", "0.1.0"), + }, + }, + }, + { + name: "Success/ValidModel", + assertion: require.NoError, + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Success/ValidModelWithChannelProperties", + assertion: require.NoError, + cfg: DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{ + addChannelProperties( + newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"}), + []property.Property{ + {Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")}, + }, + ), + }, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Success/ValidModelWithPackageProperties", + assertion: require.NoError, + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + }, + }, + { + name: "Error/Deprecation/UnspecifiedPackage", + assertion: hasError(`package name must be set for deprecation item 0`), + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + Deprecations: []Deprecation{ + {Schema: SchemaDeprecation}, + }, + }, + }, + { + name: "Error/Deprecation/OutOfBoundsBundle", + assertion: hasError(`cannot deprecate bundle "foo.v2.0.0" for package "foo": bundle not found`), + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + Deprecations: []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "foo", + Entries: []DeprecationEntry{ + {Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v2.0.0"}, Message: "foo.v2.0.0 doesn't exist in the first place"}, + }, + }, + }, + }, + }, + { + name: "Error/Deprecation/OutOfBoundsPackage", + assertion: hasError(`cannot apply deprecations to an unknown package "nyarl"`), + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + Deprecations: []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "nyarl", + }, + }, + }, + }, + { + name: "Error/Deprecation/MultiplePerPackage", + assertion: hasError(`expected a maximum of one deprecation per package: "foo"`), + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + Deprecations: []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "foo", + Entries: []DeprecationEntry{ + {Reference: PackageScopedReference{Schema: SchemaChannel, Name: "alpha"}, Message: "no more alpha channel"}, + }, + }, + { + Schema: SchemaDeprecation, + Package: "foo", + Entries: []DeprecationEntry{ + {Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v0.1.0"}, Message: "foo.v0.1.0 is dead. do another thing"}, + }, + }, + }, + }, + }, + { + name: "Error/Deprecation/BadRefSchema", + assertion: hasError(`cannot deprecate object declcfg.PackageScopedReference{Schema:"badschema", Name:"foo.v2.0.0"} referenced by entry 0 for package "foo": object schema unknown`), + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + Deprecations: []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "foo", + Entries: []DeprecationEntry{ + {Reference: PackageScopedReference{Schema: "badschema", Name: "foo.v2.0.0"}, Message: "foo.v2.0.0 doesn't exist in the first place"}, + }, + }, + }, + }, + }, + { + name: "Error/Deprecation/DuplicateRef", + assertion: hasError(`duplicate deprecation entry declcfg.PackageScopedReference{Schema:"olm.bundle", Name:"foo.v0.1.0"} for package "foo"`), + cfg: DeclarativeConfig{ + Packages: []Package{ + addPackageProperties( + newTestPackage("foo", "alpha", svgSmallCircle), + []property.Property{ + {Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")}, + }, + ), + }, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + Deprecations: []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "foo", + Entries: []DeprecationEntry{ + {Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v0.1.0"}, Message: "foo.v0.1.0 is bad"}, + {Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v0.1.0"}, Message: "foo.v0.1.0 is bad"}, + }, + }, + }, + }, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + _, err := ConvertToModel(s.cfg) + s.assertion(t, err) + }) + } +} + +func TestConvertToModelBundle(t *testing.T) { + cfg := DeclarativeConfig{ + Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)}, + Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})}, + Bundles: []Bundle{newTestBundle("foo", "0.1.0")}, + } + m, err := ConvertToModel(cfg) + require.NoError(t, err) + + pkg, ok := m["foo"] + require.True(t, ok, "expected package 'foo' to be present") + ch, ok := pkg.Channels["alpha"] + require.True(t, ok, "expected channel 'alpha' to be present") + b, ok := ch.Bundles["foo.v0.1.0"] + require.True(t, ok, "expected bundle 'foo.v0.1.0' to be present") + + assert.Equal(t, pkg, b.Package) + assert.Equal(t, ch, b.Channel) + assert.Equal(t, "foo.v0.1.0", b.Name) + assert.Equal(t, "foo-bundle:v0.1.0", b.Image) + assert.Equal(t, "", b.Replaces) + assert.Nil(t, b.Skips) + assert.Equal(t, "", b.SkipRange) + assert.Len(t, b.Properties, 3) + assert.Equal(t, []model.RelatedImage{{Name: "bundle", Image: "foo-bundle:v0.1.0"}}, b.RelatedImages) + assert.Nil(t, b.Deprecation) + assert.Len(t, b.Objects, 2) + assert.NotEmpty(t, b.CsvJSON) + assert.NotNil(t, b.PropertiesP) + assert.Len(t, b.PropertiesP.BundleObjects, 2) + assert.Len(t, b.PropertiesP.Packages, 1) + assert.Equal(t, semver.MustParse("0.1.0"), b.Version) +} + +func TestConvertToModelRoundtrip(t *testing.T) { + expected := buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: false}) // TODO: turn on deprecation when we have model-->declcfg conversion + + m, err := ConvertToModel(expected) + require.NoError(t, err) + actual := ConvertFromModel(m) + + removeJSONWhitespace(&expected) + removeJSONWhitespace(&actual) + + assert.Equal(t, expected.Packages, actual.Packages) + assert.Equal(t, expected.Bundles, actual.Bundles) + assert.Empty(t, actual.Others, "expected unrecognized schemas not to make the roundtrip") +} + +func hasError(expectedError string) require.ErrorAssertionFunc { + return func(t require.TestingT, actualError error, args ...interface{}) { + if stdt, ok := t.(*testing.T); ok { + stdt.Helper() + } + if actualError != nil && actualError.Error() == expectedError { + return + } + t.Errorf("expected error to be `%s`, got `%s`", expectedError, actualError) + t.FailNow() + } +} diff --git a/alpha/declcfg/helpers_test.go b/alpha/declcfg/helpers_test.go new file mode 100644 index 000000000..1d55f9e2a --- /dev/null +++ b/alpha/declcfg/helpers_test.go @@ -0,0 +1,364 @@ +package declcfg + +import ( + "encoding/json" + "fmt" + "sort" + "testing" + + "github.com/blang/semver/v4" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/alpha/property" +) + +type validDeclarativeConfigSpec struct { + IncludeUnrecognized bool + IncludeDeprecations bool +} + +func buildValidDeclarativeConfig(spec validDeclarativeConfigSpec) DeclarativeConfig { + a001 := newTestBundle("anakin", "0.0.1") + a010 := newTestBundle("anakin", "0.1.0") + a011 := newTestBundle("anakin", "0.1.1") + b1 := newTestBundle("boba-fett", "1.0.0") + b2 := newTestBundle("boba-fett", "2.0.0") + + var others []Meta + if spec.IncludeUnrecognized { + others = []Meta{ + {Schema: "custom.1", Blob: json.RawMessage(`{"schema": "custom.1"}`)}, + {Schema: "custom.2", Blob: json.RawMessage(`{"schema": "custom.2"}`)}, + {Schema: "custom.3", Package: "anakin", Blob: json.RawMessage(`{ + "myField": "foobar", + "package": "anakin", + "schema": "custom.3" + }`)}, + {Schema: "custom.3", Package: "boba-fett", Blob: json.RawMessage(`{ + "myField": "foobar", + "package": "boba-fett", + "schema": "custom.3" + }`)}, + } + } + + var deprecations []Deprecation + if spec.IncludeDeprecations { + deprecations = []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "anakin", + Entries: []DeprecationEntry{ + { + Reference: PackageScopedReference{ + Schema: "olm.bundle", + Name: testBundleName("anakin", "0.0.1"), + }, + Message: "This bundle version is deprecated", + }, + { + Reference: PackageScopedReference{ + Schema: "olm.channel", + Name: "light", + }, + Message: "This channel is deprecated", + }, + { + Reference: PackageScopedReference{ + Schema: "olm.package", + }, + Message: "This package is deprecated... there is another", + }, + }, + }, + } + } + + return DeclarativeConfig{ + Packages: []Package{ + newTestPackage("anakin", "dark", svgSmallCircle), + newTestPackage("boba-fett", "mando", svgBigCircle), + }, + Channels: []Channel{ + newTestChannel("anakin", "dark", + ChannelEntry{ + Name: testBundleName("anakin", "0.0.1"), + }, + ChannelEntry{ + Name: testBundleName("anakin", "0.1.0"), + Replaces: testBundleName("anakin", "0.0.1"), + }, + ChannelEntry{ + Name: testBundleName("anakin", "0.1.1"), + Replaces: testBundleName("anakin", "0.0.1"), + Skips: []string{testBundleName("anakin", "0.1.0")}, + }, + ), + newTestChannel("anakin", "light", + ChannelEntry{ + Name: testBundleName("anakin", "0.0.1"), + }, + ChannelEntry{ + Name: testBundleName("anakin", "0.1.0"), + Replaces: testBundleName("anakin", "0.0.1"), + }, + ), + newTestChannel("boba-fett", "mando", + ChannelEntry{ + Name: testBundleName("boba-fett", "1.0.0"), + }, + ChannelEntry{ + Name: testBundleName("boba-fett", "2.0.0"), + Replaces: testBundleName("boba-fett", "1.0.0"), + }, + ), + }, + Bundles: []Bundle{ + a001, a010, a011, + b1, b2, + }, + Others: others, + Deprecations: deprecations, + } +} + +type bundleOpt func(*Bundle) + +func withNoProperties() func(*Bundle) { + return func(b *Bundle) { + b.Properties = []property.Property{} + } +} + +func withNoBundleImage() func(*Bundle) { + return func(b *Bundle) { + b.Image = "" + } +} + +func withNoBundleData() func(*Bundle) { + return func(b *Bundle) { + b.Objects = []string{} + b.CsvJSON = "" + } +} + +func newTestBundle(packageName, version string, opts ...bundleOpt) Bundle { + csvJSON := fmt.Sprintf(`{"kind": "ClusterServiceVersion", "apiVersion": "operators.coreos.com/v1alpha1", "metadata":{"name":%q}}`, testBundleName(packageName, version)) + b := Bundle{ + Schema: SchemaBundle, + Name: testBundleName(packageName, version), + Package: packageName, + Image: testBundleImage(packageName, version), + Properties: []property.Property{ + property.MustBuildPackage(packageName, version), + property.MustBuildBundleObject([]byte(csvJSON)), + property.MustBuildBundleObject([]byte(`{"kind": "CustomResourceDefinition", "apiVersion": "apiextensions.k8s.io/v1"}`)), + }, + RelatedImages: []RelatedImage{ + { + Name: "bundle", + Image: testBundleImage(packageName, version), + }, + }, + CsvJSON: csvJSON, + Objects: []string{ + csvJSON, + `{"kind": "CustomResourceDefinition", "apiVersion": "apiextensions.k8s.io/v1"}`, + }, + } + for _, opt := range opts { + opt(&b) + } + sort.Slice(b.Properties, func(i, j int) bool { + if b.Properties[i].Type != b.Properties[j].Type { + return b.Properties[i].Type < b.Properties[j].Type + } + return string(b.Properties[i].Value) < string(b.Properties[j].Value) + }) + return b +} + +const ( + svgSmallCircle = `<svg viewBox="0 0 100 100"><circle cx="25" cy="25" r="25"/></svg>` + svgBigCircle = `<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="50"/></svg>` +) + +func newTestPackage(packageName, defaultChannel, svgData string) Package { + p := Package{ + Schema: SchemaPackage, + Name: packageName, + DefaultChannel: defaultChannel, + Icon: &Icon{Data: []byte(svgData), MediaType: "image/svg+xml"}, + Description: testPackageDescription(packageName), + } + return p +} + +func addPackageProperties(in Package, p []property.Property) Package { + in.Properties = p + return in +} + +func newTestChannel(packageName, channelName string, entries ...ChannelEntry) Channel { + return Channel{ + Schema: SchemaChannel, + Name: channelName, + Package: packageName, + Entries: entries, + } +} + +func addChannelProperties(in Channel, p []property.Property) Channel { + in.Properties = p + return in +} + +func buildTestModel() model.Model { + return model.Model{ + "anakin": buildAnakinPkgModel(), + "boba-fett": buildBobaFettPkgModel(), + } +} + +func getBundle(pkg *model.Package, ch *model.Channel, version, replaces string, skips ...string) *model.Bundle { + return &model.Bundle{ + Package: pkg, + Channel: ch, + Name: testBundleName(pkg.Name, version), + Image: testBundleImage(pkg.Name, version), + Properties: []property.Property{ + property.MustBuildPackage(pkg.Name, version), + property.MustBuildBundleObject([]byte(getCSVJson(pkg.Name, version))), + property.MustBuildBundleObject([]byte(getCRDJSON())), + }, + Replaces: replaces, + Skips: skips, + RelatedImages: []model.RelatedImage{{ + Name: "bundle", + Image: testBundleImage(pkg.Name, version), + }}, + CsvJSON: getCSVJson(pkg.Name, version), + Objects: []string{ + getCSVJson(pkg.Name, version), + getCRDJSON(), + }, + Version: semver.MustParse(version), + } +} + +func getCSVJson(pkgName, version string) string { + return fmt.Sprintf(`{"kind": "ClusterServiceVersion", "apiVersion": "operators.coreos.com/v1alpha1", "metadata":{"name":%q}}`, testBundleName(pkgName, version)) +} + +func getCRDJSON() string { + return `{"kind": "CustomResourceDefinition", "apiVersion": "apiextensions.k8s.io/v1"}` +} + +func buildAnakinPkgModel() *model.Package { + pkgName := "anakin" + + pkg := &model.Package{ + Name: pkgName, + Description: testPackageDescription(pkgName), + Icon: &model.Icon{ + Data: []byte(svgSmallCircle), + MediaType: "image/svg+xml", + }, + Channels: map[string]*model.Channel{}, + } + + light := &model.Channel{ + Package: pkg, + Name: "light", + Bundles: map[string]*model.Bundle{}, + } + + dark := &model.Channel{ + Package: pkg, + Name: "dark", + Bundles: map[string]*model.Bundle{}, + } + light.Bundles[testBundleName(pkgName, "0.0.1")] = getBundle(pkg, light, "0.0.1", "") + light.Bundles[testBundleName(pkgName, "0.1.0")] = getBundle(pkg, light, "0.1.0", testBundleName(pkgName, "0.0.1")) + + dark.Bundles[testBundleName(pkgName, "0.0.1")] = getBundle(pkg, dark, "0.0.1", "") + dark.Bundles[testBundleName(pkgName, "0.1.0")] = getBundle(pkg, dark, "0.1.0", testBundleName(pkgName, "0.0.1")) + dark.Bundles[testBundleName(pkgName, "0.1.1")] = getBundle(pkg, dark, "0.1.1", testBundleName(pkgName, "0.0.1"), testBundleName(pkgName, "0.1.0")) + + pkg.Channels["light"] = light + pkg.Channels["dark"] = dark + pkg.DefaultChannel = pkg.Channels["dark"] + return pkg +} + +func buildBobaFettPkgModel() *model.Package { + pkgName := "boba-fett" + pkg := &model.Package{ + Name: pkgName, + Description: testPackageDescription(pkgName), + Icon: &model.Icon{ + Data: []byte(svgBigCircle), + MediaType: "image/svg+xml", + }, + Channels: map[string]*model.Channel{}, + } + mando := &model.Channel{ + Package: pkg, + Name: "mando", + Bundles: map[string]*model.Bundle{}, + } + mando.Bundles[testBundleName(pkgName, "1.0.0")] = getBundle(pkg, mando, "1.0.0", "") + mando.Bundles[testBundleName(pkgName, "2.0.0")] = getBundle(pkg, mando, "2.0.0", testBundleName(pkgName, "1.0.0")) + pkg.Channels["mando"] = mando + pkg.DefaultChannel = mando + return pkg +} + +func testPackageDescription(pkg string) string { + return fmt.Sprintf("%s operator", pkg) +} + +func testBundleName(pkg, version string) string { + return fmt.Sprintf("%s.v%s", pkg, version) +} + +func testBundleImage(pkg, version string) string { + return fmt.Sprintf("%s-bundle:v%s", pkg, version) +} + +func equalsDeclarativeConfig(t *testing.T, expected, actual DeclarativeConfig) { + t.Helper() + removeJSONWhitespace(&expected) + removeJSONWhitespace(&actual) + + assert.ElementsMatch(t, expected.Packages, actual.Packages) + assert.ElementsMatch(t, expected.Others, actual.Others) + + // When comparing bundles, the order of properties doesn't matter. + // Unfortunately, assert.ElementsMatch() only ignores ordering of + // root elements, so we need to manually sort bundles and use + // assert.ElementsMatch on the properties fields between + // expected and actual. + require.Equal(t, len(expected.Bundles), len(actual.Bundles)) + sort.SliceStable(expected.Bundles, func(i, j int) bool { + return expected.Bundles[i].Name < expected.Bundles[j].Name + }) + sort.SliceStable(actual.Bundles, func(i, j int) bool { + return actual.Bundles[i].Name < actual.Bundles[j].Name + }) + for i := range expected.Bundles { + assert.ElementsMatch(t, expected.Bundles[i].Properties, actual.Bundles[i].Properties) + expected.Bundles[i].Properties, actual.Bundles[i].Properties = nil, nil + assert.Equal(t, expected.Bundles[i], actual.Bundles[i]) + } + + // In case new fields are added to the DeclarativeConfig struct in the future, + // test that the rest is Equal. + expected.Packages, actual.Packages = nil, nil + expected.Bundles, actual.Bundles = nil, nil + expected.Others, actual.Others = nil, nil + assert.Equal(t, expected, actual) +} diff --git a/alpha/declcfg/load.go b/alpha/declcfg/load.go new file mode 100644 index 000000000..5db111b87 --- /dev/null +++ b/alpha/declcfg/load.go @@ -0,0 +1,333 @@ +package declcfg + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "runtime" + "sync" + + "github.com/joelanford/ignore" + "golang.org/x/sync/errgroup" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/operator-framework/api/pkg/operators" + + "github.com/operator-framework/operator-registry/alpha/property" +) + +const ( + indexIgnoreFilename = ".indexignore" +) + +type WalkMetasFSFunc func(path string, meta *Meta, err error) error + +// WalkMetasFS walks the filesystem rooted at root and calls walkFn for each individual meta object found in the root. +// By default, WalkMetasFS is not thread-safe because it invokes walkFn concurrently. In order to make it thread-safe, +// use the WithConcurrency(1) to avoid concurrent invocations of walkFn. +func WalkMetasFS(ctx context.Context, root fs.FS, walkFn WalkMetasFSFunc, opts ...LoadOption) error { + if root == nil { + return fmt.Errorf("no declarative config filesystem provided") + } + + options := LoadOptions{ + concurrency: runtime.NumCPU(), + } + for _, opt := range opts { + opt(&options) + } + + pathChan := make(chan string, options.concurrency) + + // Create an errgroup to manage goroutines. The context is closed when any + // goroutine returns an error. Goroutines should check the context + // to see if they should return early (in the case of another goroutine + // returning an error). + eg, ctx := errgroup.WithContext(ctx) + + // Walk the FS and send paths to a channel for parsing. + eg.Go(func() error { + return sendPaths(ctx, root, pathChan) + }) + + // Parse paths concurrently. The waitgroup ensures that all paths are parsed + // before the cfgChan is closed. + for i := 0; i < options.concurrency; i++ { + eg.Go(func() error { + return parseMetaPaths(ctx, root, pathChan, walkFn, options) + }) + } + return eg.Wait() +} + +type WalkMetasReaderFunc func(meta *Meta, err error) error + +func WalkMetasReader(r io.Reader, walkFn WalkMetasReaderFunc) error { + dec := yaml.NewYAMLOrJSONDecoder(r, 4096) + for { + var in Meta + if err := dec.Decode(&in); err != nil { + if errors.Is(err, io.EOF) { + break + } + return walkFn(nil, err) + } + + if err := walkFn(&in, nil); err != nil { + return err + } + } + return nil +} + +type WalkFunc func(path string, cfg *DeclarativeConfig, err error) error + +// WalkFS walks root using a gitignore-style filename matcher to skip files +// that match patterns found in .indexignore files found throughout the filesystem. +// It calls walkFn for each declarative config file it finds. If WalkFS encounters +// an error loading or parsing any file, the error will be immediately returned. +func WalkFS(root fs.FS, walkFn WalkFunc) error { + return walkFiles(root, func(root fs.FS, path string, err error) error { + if err != nil { + return walkFn(path, nil, err) + } + + cfg, err := LoadFile(root, path) + if err != nil { + return walkFn(path, cfg, err) + } + + return walkFn(path, cfg, nil) + }) +} + +func walkFiles(root fs.FS, fn func(root fs.FS, path string, err error) error) error { + if root == nil { + return fmt.Errorf("no declarative config filesystem provided") + } + + matcher, err := ignore.NewMatcher(root, indexIgnoreFilename) + if err != nil { + return err + } + + return fs.WalkDir(root, ".", func(path string, info fs.DirEntry, err error) error { + if err != nil { + return fn(root, path, err) + } + // avoid validating a directory, an .indexignore file, or any file that matches + // an ignore pattern outlined in a .indexignore file. + if info.IsDir() || info.Name() == indexIgnoreFilename || matcher.Match(path, false) { + return nil + } + + return fn(root, path, nil) + }) +} + +type LoadOptions struct { + concurrency int +} + +type LoadOption func(*LoadOptions) + +func WithConcurrency(concurrency int) LoadOption { + return func(opts *LoadOptions) { + opts.concurrency = concurrency + } +} + +// LoadFS loads a declarative config from the provided root FS. LoadFS walks the +// filesystem from root and uses a gitignore-style filename matcher to skip files +// that match patterns found in .indexignore files found throughout the filesystem. +// If LoadFS encounters an error loading or parsing any file, the error will be +// immediately returned. +func LoadFS(ctx context.Context, root fs.FS, opts ...LoadOption) (*DeclarativeConfig, error) { + builder := fbcBuilder{} + if err := WalkMetasFS(ctx, root, func(path string, meta *Meta, err error) error { + if err != nil { + return err + } + return builder.addMeta(meta) + }, opts...); err != nil { + return nil, err + } + return &builder.cfg, nil +} + +func sendPaths(ctx context.Context, root fs.FS, pathChan chan<- string) error { + defer close(pathChan) + return walkFiles(root, func(_ fs.FS, path string, err error) error { + if err != nil { + return err + } + select { + case pathChan <- path: + case <-ctx.Done(): // don't block on sending to pathChan + return ctx.Err() + } + return nil + }) +} + +func parseMetaPaths(ctx context.Context, root fs.FS, pathChan <-chan string, walkFn WalkMetasFSFunc, _ LoadOptions) error { + for { + select { + case <-ctx.Done(): // don't block on receiving from pathChan + return ctx.Err() + case path, ok := <-pathChan: + if !ok { + return nil + } + err := func() error { // using closure to ensure file is closed immediately after use + file, err := root.Open(path) + if err != nil { + return err + } + defer file.Close() + + return WalkMetasReader(file, func(meta *Meta, err error) error { + return walkFn(path, meta, err) + }) + }() + if err != nil { + return err + } + } + } +} + +func readBundleObjects(b *Bundle) error { + var obj property.BundleObject + for i, props := range b.Properties { + if props.Type != property.TypeBundleObject { + continue + } + if err := json.Unmarshal(props.Value, &obj); err != nil { + return fmt.Errorf("package %q, bundle %q: parse property at index %d as bundle object: %v", b.Package, b.Name, i, err) + } + objJSON, err := yaml.ToJSON(obj.Data) + if err != nil { + return fmt.Errorf("package %q, bundle %q: convert bundle object property at index %d to JSON: %v", b.Package, b.Name, i, err) + } + b.Objects = append(b.Objects, string(objJSON)) + } + b.CsvJSON = extractCSV(b.Objects) + return nil +} + +func extractCSV(objs []string) string { + for _, obj := range objs { + u := unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(obj), &u); err != nil { + continue + } + if u.GetKind() == operators.ClusterServiceVersionKind { + return obj + } + } + return "" +} + +// LoadReader reads yaml or json from the passed in io.Reader and unmarshals it into a DeclarativeConfig struct. +func LoadReader(r io.Reader) (*DeclarativeConfig, error) { + builder := fbcBuilder{} + if err := WalkMetasReader(r, func(meta *Meta, err error) error { + if err != nil { + return err + } + return builder.addMeta(meta) + }); err != nil { + return nil, err + } + return &builder.cfg, nil +} + +// LoadFile will unmarshall declarative config components from a single filename provided in 'path' +// located at a filesystem hierarchy 'root' +func LoadFile(root fs.FS, path string) (*DeclarativeConfig, error) { + file, err := root.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + cfg, err := LoadReader(file) + if err != nil { + return nil, err + } + + return cfg, nil +} + +// LoadSlice will compose declarative config components from a slice of Meta objects +func LoadSlice(metas []*Meta) (*DeclarativeConfig, error) { + builder := fbcBuilder{} + for _, meta := range metas { + if err := builder.addMeta(meta); err != nil { + return nil, err + } + } + return &builder.cfg, nil +} + +type fbcBuilder struct { + cfg DeclarativeConfig + + packagesMu sync.Mutex + channelsMu sync.Mutex + bundlesMu sync.Mutex + deprecationsMu sync.Mutex + othersMu sync.Mutex +} + +func (c *fbcBuilder) addMeta(in *Meta) error { + switch in.Schema { + case SchemaPackage: + var p Package + if err := json.Unmarshal(in.Blob, &p); err != nil { + return fmt.Errorf("parse package: %v", err) + } + c.packagesMu.Lock() + c.cfg.Packages = append(c.cfg.Packages, p) + c.packagesMu.Unlock() + case SchemaChannel: + var ch Channel + if err := json.Unmarshal(in.Blob, &ch); err != nil { + return fmt.Errorf("parse channel: %v", err) + } + c.channelsMu.Lock() + c.cfg.Channels = append(c.cfg.Channels, ch) + c.channelsMu.Unlock() + case SchemaBundle: + var b Bundle + if err := json.Unmarshal(in.Blob, &b); err != nil { + return fmt.Errorf("parse bundle: %v", err) + } + if err := readBundleObjects(&b); err != nil { + return fmt.Errorf("read bundle objects: %v", err) + } + c.bundlesMu.Lock() + c.cfg.Bundles = append(c.cfg.Bundles, b) + c.bundlesMu.Unlock() + case SchemaDeprecation: + var d Deprecation + if err := json.Unmarshal(in.Blob, &d); err != nil { + return fmt.Errorf("parse deprecation: %w", err) + } + c.deprecationsMu.Lock() + c.cfg.Deprecations = append(c.cfg.Deprecations, d) + c.deprecationsMu.Unlock() + case "": + return fmt.Errorf("object '%s' is missing root schema field", string(in.Blob)) + default: + c.othersMu.Lock() + c.cfg.Others = append(c.cfg.Others, *in) + c.othersMu.Unlock() + } + return nil +} diff --git a/alpha/declcfg/load_benchmark_test.go b/alpha/declcfg/load_benchmark_test.go new file mode 100644 index 000000000..46f3138be --- /dev/null +++ b/alpha/declcfg/load_benchmark_test.go @@ -0,0 +1,312 @@ +package declcfg_test + +import ( + "context" + "crypto/rand" + "encoding/base64" + "fmt" + "math/big" + "os" + "runtime" + "testing" + + "github.com/blang/semver/v4" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/operator-framework/api/pkg/lib/version" + "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func BenchmarkLoadFS(b *testing.B) { + fbc := generateFBC(b, 300, 450, 3000) + b.ResetTimer() + + for _, n := range []int{1, runtime.NumCPU(), 2 * runtime.NumCPU()} { + b.Run(fmt.Sprintf("%d routines", n), func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + tempDir := b.TempDir() + if err := declcfg.WriteFS(*fbc, tempDir, declcfg.WriteJSON, ".json"); err != nil { + b.Error(err) + } + b.StartTimer() + + _, err := declcfg.LoadFS(context.Background(), os.DirFS(tempDir), declcfg.WithConcurrency(n)) + if err != nil { + b.Error(err) + } + } + }) + } +} + +const randomPng = "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" + +func generateFBC(b *testing.B, numPackages, numChannels, numBundles int) *declcfg.DeclarativeConfig { + pngData, err := base64.StdEncoding.DecodeString(randomPng) + if err != nil { + b.Error(err) + } + + fbc := &declcfg.DeclarativeConfig{} + + for i := 0; i < numPackages; i++ { + pkgName := fmt.Sprintf("pkg-%d", i) + fbc.Packages = append(fbc.Packages, declcfg.Package{ + Schema: declcfg.SchemaPackage, + Name: pkgName, + Description: fmt.Sprintf("%s description", pkgName), + Icon: &declcfg.Icon{ + Data: pngData, + MediaType: "image/png", + }, + }) + } + for i := 0; i < numChannels; i++ { + r, err := rand.Int(rand.Reader, big.NewInt(int64(numPackages))) + if err != nil { + b.Error(err) + } + pkgName := fbc.Packages[r.Int64()].Name + channelName := fmt.Sprintf("channel-%d", i) + fbc.Channels = append(fbc.Channels, declcfg.Channel{ + Schema: declcfg.SchemaChannel, + Package: pkgName, + Name: channelName, + }) + } + for i := 0; i < numBundles; i++ { + r, err := rand.Int(rand.Reader, big.NewInt(int64(numPackages))) + if err != nil { + b.Error(err) + } + pkgName := fbc.Packages[r.Int64()].Name + bundleName := fmt.Sprintf("bundle-%d", i) + version := fmt.Sprintf("0.%d.0", i) + bundle := declcfg.Bundle{ + Schema: declcfg.SchemaBundle, + Package: pkgName, + Image: fmt.Sprintf("bundles/%s", bundleName), + Properties: []property.Property{ + property.MustBuildPackage(pkgName, version), + property.MustBuildGVK("apps", "Deployment", "v1"), + property.MustBuildGVK("apps", "DaemonSet", "v1"), + property.MustBuildGVKRequired("", "Service", "v1"), + property.MustBuildPackageRequired("foo", "0.0.1"), + }, + } + + csv := genCsv(pkgName, version) + bundle.Properties = append(bundle.Properties, property.MustBuildCSVMetadata(csv)) + fbc.Bundles = append(fbc.Bundles, bundle) + + p, err := rand.Int(rand.Reader, big.NewInt(int64(numChannels))) + if err != nil { + b.Error(err) + } + chIdx := p.Int64() + ch := fbc.Channels[chIdx] + replaces := "" + if len(ch.Entries) > 0 { + replaces = ch.Entries[len(ch.Entries)-1].Name + } + ch.Entries = append(ch.Entries, declcfg.ChannelEntry{ + Name: bundleName, + Replaces: replaces, + }) + fbc.Channels[chIdx] = ch + } + + return fbc +} + +func genCsv(pkgName, ver string) v1alpha1.ClusterServiceVersion { + csv := v1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterServiceVersion", + APIVersion: "operators.coreos.com/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s.v%s", pkgName, ver), + Annotations: map[string]string{ + "alm-examples": `[ + { + "apiVersion": "example.com/v1alpha1", + "kind": "Example", + "metadata": { + "name": "example-sample" + }, + "spec": { + "image":{ + "repository":"example/example", + "tag":"v0.0.1", + "pullPolicy":"IfNotPresent", + "credentials":{} + }, + "labels":{}, + "conf":{ + "log":{"enabled":false,"config":{}}, + "logtostderr":"INFO", + "port":26257, + "http-port":8080, + "store":{"enabled":false,"type":null,"size":null,"attrs":null}}, + "statefulset":{ + "replicas":3, + "updateStrategy":{"type":"RollingUpdate"}, + "podManagementPolicy":"Parallel", + "budget":{"maxUnavailable":1}, + "args":[], + "env":[], + "secretMounts":[], + "labels":{"app.kubernetes.io/component":"example"}, + "annotations":{}, + "nodeAffinity":{}, + "podAffinity":{}, + "podAntiAffinity":{"topologyKey":"kubernetes.io/hostname","type":"soft","weight":100}, + "nodeSelector":{}, + "priorityClassName":"", + "tolerations":[], + "topologySpreadConstraints":{"maxSkew":1,"topologyKey":"topology.kubernetes.io/zone","whenUnsatisfiable":"ScheduleAnyway"}, + "resources":{}, + "customLivenessProbe":{}, + "customReadinessProbe":{} + }, + "ingress":{"enabled":false,"labels":{},"annotations":{},"paths":["/"],"hosts":[],"tls":[]}, + "prometheus":{"enabled":true}, + "serviceMonitor":{"enabled":false,"labels":{},"annotations":{},"interval":"10s","namespaced":false}, + "storage":{"hostPath":"","persistentVolume":{"enabled":true,"size":"100Gi","storageClass":"","labels":{},"annotations":{}}} + } + } + } + ]`, + "capabilities": "Basic Install", + "categories": "Application", + "certified": "false", + "containerImage": "quay.io/example/example:v0.0.1", + "createdAt": "1970-01-01T00-00-00Z", + "description": "Example Operator", + "operators.operatorframework.io/builder": "operator-sdk-v1.0.0", + "operators.operatorframework.io/project_layout": "go.sdk.operatorframework.io/v3", + "repository": "https://github.com/example/example", + "support": "Example, Inc.", + "olm.skipRange": "<0.0.1", + }, + }, + Spec: v1alpha1.ClusterServiceVersionSpec{ + Icon: []v1alpha1.Icon{ + { + Data: randomPng, + MediaType: "image/png", + }, + }, + CustomResourceDefinitions: v1alpha1.CustomResourceDefinitions{ + Owned: []v1alpha1.CRDDescription{ + { + Description: "Represents an Example instance", + DisplayName: "Example", + Kind: "Example", + Version: "v1alpha1", + Name: "examples.example.com", + Resources: []v1alpha1.APIResourceReference{ + { + Kind: "Deployment", + Version: "apps/v1", + }, + { + Kind: "Service", + Version: "v1", + }, + { + Kind: "ReplicaSet", + Version: "apps/v1", + }, + { + Kind: "Pod", + Version: "v1", + }, + { + Kind: "Secret", + Version: "v1", + }, + { + Kind: "ConfigMap", + Version: "v1", + }, + { + Kind: "PresistentVolumeClaim", + Version: "v1", + }, + { + Kind: "StatefulSet", + Version: "apps/v1", + }, + { + Kind: "Job", + Version: "batch/v1", + }, + }, + }, + }, + }, + DisplayName: "Example Operator", + InstallModes: []v1alpha1.InstallMode{ + { + Type: v1alpha1.InstallModeTypeOwnNamespace, + Supported: false, + }, + { + Type: v1alpha1.InstallModeTypeSingleNamespace, + Supported: false, + }, + { + Type: v1alpha1.InstallModeTypeMultiNamespace, + Supported: false, + }, + { + Type: v1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + Keywords: []string{"example", "application", "sample", "foobar"}, + Links: []v1alpha1.AppLink{ + { + Name: "Example Operator", + URL: "https://www.example.com/operator", + }, + { + Name: "Example Operator Documentation", + URL: "https://www.example.com/operator/docs", + }, + { + Name: "Example Operator Support", + URL: "https://www.example.com/operator/support", + }, + { + Name: "Example Operator Source Code", + URL: "https://github.com/example/operator", + }, + }, + Maintainers: []v1alpha1.Maintainer{ + { + Email: "janedoe@example.com", + Name: "Jane Doe", + }, + { + Email: "johndoe@example.com", + Name: "John Doe", + }, + }, + Maturity: "alpha", + MinKubeVersion: "1.21.0", + Provider: v1alpha1.AppLink{ + Name: "Example, Inc.", + URL: "https://www.example.com", + }, + Version: version.OperatorVersion{Version: semver.MustParse(ver)}, + }, + } + return csv +} diff --git a/alpha/declcfg/load_test.go b/alpha/declcfg/load_test.go new file mode 100644 index 000000000..392fbd795 --- /dev/null +++ b/alpha/declcfg/load_test.go @@ -0,0 +1,1032 @@ +package declcfg + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io/fs" + "os" + "sync" + "testing" + "testing/fstest" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/operator-framework/operator-registry/alpha/property" +) + +func TestLoadReader(t *testing.T) { + type spec struct { + name string + fsys fs.FS + path string + assertion require.ErrorAssertionFunc + expectNumPackages int + expectNumBundles int + expectNumOthers int + } + specs := []spec{ + { + name: "Error/NotYAMLOrJSON", + fsys: invalidFS, + path: "invalid-format.txt", + assertion: require.Error, + }, + { + name: "Error/NotJSONObject", + fsys: invalidFS, + path: "not-object.json", + assertion: require.Error, + }, + { + name: "Error/NoSchema", + fsys: invalidFS, + path: "no-schema.yaml", + assertion: require.Error, + }, + { + name: "Error/InvalidPackageJSON", + fsys: invalidFS, + path: "invalid-package.json", + assertion: require.Error, + }, + { + name: "Error/InvalidBundleJSON", + fsys: invalidFS, + path: "invalid-bundle.json", + assertion: require.Error, + }, + { + name: "Success/UnrecognizedSchema", + fsys: validFS, + path: "unrecognized-schema.json", + assertion: require.NoError, + expectNumPackages: 1, + expectNumBundles: 1, + expectNumOthers: 1, + }, + { + name: "Success/ValidFile", + fsys: validFS, + path: "etcd.yaml", + assertion: require.NoError, + expectNumPackages: 1, + expectNumBundles: 6, + expectNumOthers: 0, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + f, err := s.fsys.Open(s.path) + require.NoError(t, err) + + cfg, err := LoadReader(f) + s.assertion(t, err) + if err == nil { + require.NotNil(t, cfg) + assert.Equal(t, len(cfg.Packages), s.expectNumPackages, "unexpected package count") + assert.Equal(t, len(cfg.Bundles), s.expectNumBundles, "unexpected bundle count") + assert.Equal(t, len(cfg.Others), s.expectNumOthers, "unexpected others count") + } + }) + } +} + +func TestWalkMetasFS(t *testing.T) { + type spec struct { + name string + fsys fs.FS + assertion require.ErrorAssertionFunc + expectNumPackages int + expectNumChannels int + expectNumBundles int + expectNumDeprecations int + expectNumOthers int + } + specs := []spec{ + { + name: "Error/NilFS", + fsys: nil, + assertion: require.Error, + }, + { + name: "Error/NonExistentDir", + fsys: os.DirFS("non/existent/dir/"), + assertion: require.Error, + }, + { + name: "Error/Invalid", + fsys: invalidFS, + assertion: require.Error, + }, + { + name: "Success/ValidDir", + fsys: validFS, + assertion: require.NoError, + expectNumPackages: 3, + expectNumChannels: 0, + expectNumBundles: 12, + expectNumDeprecations: 1, + expectNumOthers: 1, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + var mu sync.Mutex + numPackages, numChannels, numBundles, numDeprecations, numOthers := 0, 0, 0, 0, 0 + err := WalkMetasFS(context.Background(), s.fsys, func(path string, meta *Meta, err error) error { + if err != nil { + return err + } + mu.Lock() + defer mu.Unlock() + switch meta.Schema { + case SchemaPackage: + numPackages++ + case SchemaChannel: + numChannels++ + case SchemaBundle: + numBundles++ + case SchemaDeprecation: + numDeprecations++ + default: + numOthers++ + } + return nil + }) + s.assertion(t, err) + if err == nil { + assert.Equal(t, s.expectNumPackages, numPackages, "unexpected package count") + assert.Equal(t, s.expectNumChannels, numChannels, "unexpected channel count") + assert.Equal(t, s.expectNumBundles, numBundles, "unexpected bundle count") + assert.Equal(t, s.expectNumOthers, numOthers, "unexpected others count") + } + }) + } +} + +func TestLoadFS(t *testing.T) { + type spec struct { + name string + fsys fs.FS + assertion require.ErrorAssertionFunc + expected *DeclarativeConfig + } + specs := []spec{ + { + name: "Error/NilFS", + fsys: nil, + assertion: require.Error, + }, + { + name: "Error/NonExistentDir", + fsys: os.DirFS("non/existent/dir/"), + assertion: require.Error, + }, + { + name: "Error/Invalid", + fsys: invalidFS, + assertion: require.Error, + }, + { + name: "Success/ValidDir", + fsys: validFS, + assertion: require.NoError, + expected: &DeclarativeConfig{ + Packages: []Package{ + {Schema: "olm.package", Name: "cockroachdb", DefaultChannel: "stable-5.x", Icon: &Icon{Data: []uint8{0x3c, 0x73, 0x76, 0x67, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x73, 0x76, 0x67, 0x22, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6f, 0x78, 0x3d, 0x22, 0x30, 0x20, 0x30, 0x20, 0x33, 0x31, 0x2e, 0x38, 0x32, 0x20, 0x33, 0x32, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x32, 0x34, 0x38, 0x36, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x35, 0x30, 0x30, 0x22, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x43, 0x4c, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x31, 0x39, 0x2e, 0x34, 0x32, 0x20, 0x39, 0x2e, 0x31, 0x37, 0x61, 0x31, 0x35, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x31, 0x2e, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x34, 0x36, 0x20, 0x31, 0x35, 0x2e, 0x34, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x31, 0x2d, 0x2e, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x33, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x33, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x2e, 0x35, 0x31, 0x2d, 0x33, 0x2e, 0x39, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x37, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x37, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x2e, 0x35, 0x31, 0x20, 0x33, 0x2e, 0x39, 0x31, 0x7a, 0x4d, 0x33, 0x30, 0x20, 0x2e, 0x35, 0x37, 0x41, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x32, 0x35, 0x2e, 0x35, 0x39, 0x20, 0x30, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x36, 0x38, 0x20, 0x32, 0x2e, 0x39, 0x33, 0x41, 0x31, 0x37, 0x2e, 0x33, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x38, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x36, 0x2e, 0x32, 0x33, 0x20, 0x30, 0x61, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x34, 0x2e, 0x34, 0x34, 0x2e, 0x35, 0x37, 0x41, 0x31, 0x36, 0x2e, 0x32, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2e, 0x31, 0x33, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x38, 0x33, 0x20, 0x31, 0x2e, 0x35, 0x37, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x2e, 0x38, 0x31, 0x2d, 0x2e, 0x35, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x31, 0x2e, 0x35, 0x39, 0x20, 0x31, 0x2e, 0x38, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x35, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x35, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x2e, 0x37, 0x38, 0x20, 0x34, 0x2e, 0x34, 0x38, 0x63, 0x2d, 0x2e, 0x32, 0x2e, 0x33, 0x32, 0x2d, 0x2e, 0x33, 0x37, 0x2e, 0x36, 0x35, 0x2d, 0x2e, 0x35, 0x35, 0x20, 0x31, 0x73, 0x2d, 0x2e, 0x32, 0x32, 0x2e, 0x34, 0x35, 0x2d, 0x2e, 0x33, 0x33, 0x2e, 0x36, 0x39, 0x2d, 0x2e, 0x33, 0x31, 0x2e, 0x37, 0x32, 0x2d, 0x2e, 0x34, 0x34, 0x20, 0x31, 0x2e, 0x30, 0x38, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x36, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x34, 0x2e, 0x32, 0x39, 0x20, 0x31, 0x38, 0x2e, 0x37, 0x63, 0x2e, 0x32, 0x36, 0x2e, 0x32, 0x35, 0x2e, 0x35, 0x33, 0x2e, 0x34, 0x39, 0x2e, 0x38, 0x31, 0x2e, 0x37, 0x33, 0x73, 0x2e, 0x34, 0x34, 0x2e, 0x33, 0x37, 0x2e, 0x36, 0x37, 0x2e, 0x35, 0x34, 0x2e, 0x35, 0x39, 0x2e, 0x34, 0x34, 0x2e, 0x38, 0x39, 0x2e, 0x36, 0x34, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x63, 0x2e, 0x33, 0x2d, 0x2e, 0x32, 0x31, 0x2e, 0x36, 0x2d, 0x2e, 0x34, 0x32, 0x2e, 0x38, 0x39, 0x2d, 0x2e, 0x36, 0x34, 0x73, 0x2e, 0x34, 0x35, 0x2d, 0x2e, 0x33, 0x35, 0x2e, 0x36, 0x37, 0x2d, 0x2e, 0x35, 0x34, 0x2e, 0x35, 0x35, 0x2d, 0x2e, 0x34, 0x38, 0x2e, 0x38, 0x31, 0x2d, 0x2e, 0x37, 0x33, 0x61, 0x31, 0x37, 0x2e, 0x34, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x35, 0x2e, 0x33, 0x38, 0x2d, 0x31, 0x32, 0x2e, 0x36, 0x31, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x33, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x31, 0x2e, 0x30, 0x39, 0x2d, 0x36, 0x2e, 0x30, 0x39, 0x63, 0x2d, 0x2e, 0x31, 0x34, 0x2d, 0x2e, 0x33, 0x37, 0x2d, 0x2e, 0x32, 0x39, 0x2d, 0x2e, 0x37, 0x33, 0x2d, 0x2e, 0x34, 0x35, 0x2d, 0x31, 0x2e, 0x30, 0x39, 0x73, 0x2d, 0x2e, 0x32, 0x32, 0x2d, 0x2e, 0x34, 0x37, 0x2d, 0x2e, 0x33, 0x33, 0x2d, 0x2e, 0x36, 0x39, 0x2d, 0x2e, 0x33, 0x35, 0x2d, 0x2e, 0x36, 0x36, 0x2d, 0x2e, 0x35, 0x35, 0x2d, 0x31, 0x61, 0x31, 0x37, 0x2e, 0x36, 0x31, 0x20, 0x31, 0x37, 0x2e, 0x36, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x2e, 0x37, 0x38, 0x2d, 0x34, 0x2e, 0x34, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x31, 0x2e, 0x36, 0x2d, 0x31, 0x2e, 0x38, 0x34, 0x20, 0x31, 0x36, 0x2e, 0x31, 0x33, 0x20, 0x31, 0x36, 0x2e, 0x31, 0x33, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x2e, 0x38, 0x31, 0x2e, 0x35, 0x34, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2e, 0x30, 0x38, 0x20, 0x30, 0x71, 0x2e, 0x34, 0x34, 0x2d, 0x2e, 0x37, 0x36, 0x2e, 0x38, 0x32, 0x2d, 0x31, 0x2e, 0x35, 0x36, 0x61, 0x2e, 0x30, 0x37, 0x2e, 0x30, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x2e, 0x30, 0x39, 0x41, 0x31, 0x36, 0x2e, 0x38, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x38, 0x39, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x2e, 0x35, 0x37, 0x7a, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x31, 0x35, 0x31, 0x66, 0x33, 0x34, 0x22, 0x2f, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x32, 0x31, 0x2e, 0x38, 0x32, 0x20, 0x31, 0x37, 0x2e, 0x34, 0x37, 0x61, 0x31, 0x35, 0x2e, 0x35, 0x31, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x31, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x34, 0x2e, 0x32, 0x35, 0x20, 0x31, 0x30, 0x2e, 0x36, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x36, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x2e, 0x37, 0x32, 0x2d, 0x34, 0x2e, 0x36, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x34, 0x2e, 0x32, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x39, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x32, 0x20, 0x31, 0x35, 0x2e, 0x36, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x2e, 0x37, 0x32, 0x20, 0x34, 0x2e, 0x36, 0x38, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x33, 0x34, 0x38, 0x35, 0x34, 0x30, 0x22, 0x2f, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x31, 0x35, 0x20, 0x32, 0x33, 0x2e, 0x34, 0x38, 0x61, 0x31, 0x35, 0x2e, 0x35, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x2e, 0x37, 0x32, 0x20, 0x34, 0x2e, 0x36, 0x38, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x33, 0x2e, 0x35, 0x33, 0x2d, 0x31, 0x35, 0x2e, 0x33, 0x37, 0x41, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x31, 0x35, 0x2e, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x31, 0x35, 0x20, 0x32, 0x33, 0x2e, 0x34, 0x38, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x37, 0x64, 0x62, 0x63, 0x34, 0x32, 0x22, 0x2f, 0x3e, 0x3c, 0x2f, 0x73, 0x76, 0x67, 0x3e}, MediaType: "image/svg+xml"}, Description: ""}, + {Schema: "olm.package", Name: "etcd", DefaultChannel: "singlenamespace-alpha", Icon: &Icon{Data: []uint8{0x3c, 0x73, 0x76, 0x67, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x32, 0x35, 0x30, 0x30, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x22, 0x32, 0x34, 0x32, 0x32, 0x22, 0x20, 0x76, 0x69, 0x65, 0x77, 0x42, 0x6f, 0x78, 0x3d, 0x22, 0x30, 0x20, 0x30, 0x20, 0x32, 0x35, 0x36, 0x20, 0x32, 0x34, 0x38, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x32, 0x30, 0x30, 0x30, 0x2f, 0x73, 0x76, 0x67, 0x22, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x41, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x22, 0x78, 0x4d, 0x69, 0x64, 0x59, 0x4d, 0x69, 0x64, 0x22, 0x3e, 0x3c, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x3d, 0x22, 0x4d, 0x32, 0x35, 0x32, 0x2e, 0x33, 0x38, 0x36, 0x20, 0x31, 0x32, 0x38, 0x2e, 0x30, 0x36, 0x34, 0x63, 0x2d, 0x31, 0x2e, 0x32, 0x30, 0x32, 0x2e, 0x31, 0x2d, 0x32, 0x2e, 0x34, 0x31, 0x2e, 0x31, 0x34, 0x37, 0x2d, 0x33, 0x2e, 0x36, 0x39, 0x33, 0x2e, 0x31, 0x34, 0x37, 0x2d, 0x37, 0x2e, 0x34, 0x34, 0x36, 0x20, 0x30, 0x2d, 0x31, 0x34, 0x2e, 0x36, 0x37, 0x2d, 0x31, 0x2e, 0x37, 0x34, 0x36, 0x2d, 0x32, 0x31, 0x2e, 0x31, 0x38, 0x37, 0x2d, 0x34, 0x2e, 0x39, 0x34, 0x34, 0x20, 0x32, 0x2e, 0x31, 0x37, 0x2d, 0x31, 0x32, 0x2e, 0x34, 0x34, 0x37, 0x20, 0x33, 0x2e, 0x30, 0x39, 0x32, 0x2d, 0x32, 0x34, 0x2e, 0x39, 0x38, 0x37, 0x20, 0x32, 0x2e, 0x38, 0x35, 0x2d, 0x33, 0x37, 0x2e, 0x34, 0x38, 0x31, 0x2d, 0x37, 0x2e, 0x30, 0x36, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x32, 0x32, 0x2d, 0x31, 0x35, 0x2e, 0x31, 0x34, 0x2d, 0x31, 0x39, 0x2e, 0x38, 0x36, 0x33, 0x2d, 0x32, 0x34, 0x2e, 0x32, 0x35, 0x36, 0x2d, 0x32, 0x38, 0x2e, 0x37, 0x34, 0x37, 0x20, 0x33, 0x2e, 0x39, 0x35, 0x35, 0x2d, 0x37, 0x2e, 0x34, 0x31, 0x35, 0x20, 0x39, 0x2e, 0x38, 0x30, 0x31, 0x2d, 0x31, 0x33, 0x2e, 0x37, 0x39, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x2d, 0x31, 0x38, 0x2e, 0x33, 0x31, 0x39, 0x6c, 0x33, 0x2e, 0x31, 0x33, 0x33, 0x2d, 0x31, 0x2e, 0x39, 0x33, 0x37, 0x2d, 0x32, 0x2e, 0x34, 0x34, 0x32, 0x2d, 0x32, 0x2e, 0x37, 0x35, 0x34, 0x63, 0x2d, 0x31, 0x32, 0x2e, 0x35, 0x38, 0x31, 0x2d, 0x31, 0x34, 0x2e, 0x31, 0x36, 0x37, 0x2d, 0x32, 0x37, 0x2e, 0x35, 0x39, 0x36, 0x2d, 0x32, 0x35, 0x2e, 0x31, 0x32, 0x2d, 0x34, 0x34, 0x2e, 0x36, 0x32, 0x2d, 0x33, 0x32, 0x2e, 0x35, 0x35, 0x32, 0x4c, 0x31, 0x37, 0x35, 0x2e, 0x38, 0x37, 0x36, 0x20, 0x30, 0x6c, 0x2d, 0x2e, 0x38, 0x36, 0x32, 0x20, 0x33, 0x2e, 0x35, 0x38, 0x38, 0x63, 0x2d, 0x32, 0x2e, 0x30, 0x33, 0x20, 0x38, 0x2e, 0x33, 0x36, 0x33, 0x2d, 0x36, 0x2e, 0x32, 0x37, 0x34, 0x20, 0x31, 0x35, 0x2e, 0x39, 0x30, 0x38, 0x2d, 0x31, 0x32, 0x2e, 0x31, 0x20, 0x32, 0x31, 0x2e, 0x39, 0x36, 0x32, 0x61, 0x31, 0x39, 0x33, 0x2e, 0x38, 0x34, 0x32, 0x20, 0x31, 0x39, 0x33, 0x2e, 0x38, 0x34, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x2d, 0x33, 0x34, 0x2e, 0x39, 0x35, 0x36, 0x2d, 0x31, 0x34, 0x2e, 0x34, 0x30, 0x35, 0x41, 0x31, 0x39, 0x34, 0x2e, 0x30, 0x31, 0x32, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x30, 0x31, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x39, 0x33, 0x2e, 0x30, 0x35, 0x36, 0x20, 0x32, 0x35, 0x2e, 0x35, 0x32, 0x43, 0x38, 0x37, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x37, 0x33, 0x20, 0x38, 0x33, 0x2e, 0x30, 0x32, 0x20, 0x31, 0x31, 0x2e, 0x39, 0x34, 0x37, 0x20, 0x38, 0x30, 0x2e, 0x39, 0x39, 0x39, 0x20, 0x33, 0x2e, 0x36, 0x30, 0x38, 0x4c, 0x38, 0x30, 0x2e, 0x31, 0x33, 0x2e, 0x30, 0x32, 0x6c, 0x2d, 0x33, 0x2e, 0x33, 0x38, 0x32, 0x20, 0x31, 0x2e, 0x34, 0x37, 0x43, 0x35, 0x39, 0x2e, 0x39, 0x33, 0x39, 0x20, 0x38, 0x2e, 0x38, 0x31, 0x35, 0x20, 0x34, 0x34, 0x2e, 0x35, 0x31, 0x20, 0x32, 0x30, 0x2e, 0x30, 0x36, 0x35, 0x20, 0x33, 0x32, 0x2e, 0x31, 0x33, 0x35, 0x20, 0x33, 0x34, 0x2e, 0x30, 0x32, 0x6c, 0x2d, 0x32, 0x2e, 0x34, 0x34, 0x39, 0x20, 0x32, 0x2e, 0x37, 0x36, 0x20, 0x33, 0x2e, 0x31, 0x33, 0x20, 0x31, 0x2e, 0x39, 0x33, 0x37, 0x63, 0x37, 0x2e, 0x32, 0x37, 0x36, 0x20, 0x34, 0x2e, 0x35, 0x30, 0x36, 0x20, 0x31, 0x33, 0x2e, 0x31, 0x30, 0x36, 0x20, 0x31, 0x30, 0x2e, 0x38, 0x34, 0x39, 0x20, 0x31, 0x37, 0x2e, 0x30, 0x35, 0x34, 0x20, 0x31, 0x38, 0x2e, 0x32, 0x32, 0x33, 0x2d, 0x39, 0x2e, 0x30, 0x38, 0x38, 0x20, 0x38, 0x2e, 0x38, 0x35, 0x2d, 0x31, 0x37, 0x2e, 0x31, 0x35, 0x34, 0x20, 0x31, 0x38, 0x2e, 0x34, 0x36, 0x32, 0x2d, 0x32, 0x34, 0x2e, 0x32, 0x31, 0x34, 0x20, 0x32, 0x38, 0x2e, 0x36, 0x33, 0x35, 0x2d, 0x2e, 0x32, 0x37, 0x35, 0x20, 0x31, 0x32, 0x2e, 0x34, 0x38, 0x39, 0x2e, 0x36, 0x20, 0x32, 0x35, 0x2e, 0x31, 0x32, 0x20, 0x32, 0x2e, 0x37, 0x38, 0x20, 0x33, 0x37, 0x2e, 0x37, 0x34, 0x2d, 0x36, 0x2e, 0x34, 0x38, 0x34, 0x20, 0x33, 0x2e, 0x31, 0x36, 0x37, 0x2d, 0x31, 0x33, 0x2e, 0x36, 0x36, 0x38, 0x20, 0x34, 0x2e, 0x38, 0x39, 0x34, 0x2d, 0x32, 0x31, 0x2e, 0x30, 0x36, 0x35, 0x20, 0x34, 0x2e, 0x38, 0x39, 0x34, 0x2d, 0x31, 0x2e, 0x32, 0x39, 0x38, 0x20, 0x30, 0x2d, 0x32, 0x2e, 0x35, 0x31, 0x33, 0x2d, 0x2e, 0x30, 0x34, 0x37, 0x2d, 0x33, 0x2e, 0x36, 0x39, 0x33, 0x2d, 0x2e, 0x31, 0x34, 0x35, 0x4c, 0x30, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x37, 0x38, 0x35, 0x6c, 0x2e, 0x33, 0x34, 0x35, 0x20, 0x33, 0x2e, 0x36, 0x37, 0x31, 0x63, 0x31, 0x2e, 0x38, 0x30, 0x32, 0x20, 0x31, 0x38, 0x2e, 0x35, 0x37, 0x38, 0x20, 0x37, 0x2e, 0x35, 0x37, 0x20, 0x33, 0x36, 0x2e, 0x32, 0x34, 0x37, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x35, 0x34, 0x20, 0x35, 0x32, 0x2e, 0x35, 0x32, 0x33, 0x6c, 0x31, 0x2e, 0x38, 0x37, 0x20, 0x33, 0x2e, 0x31, 0x37, 0x36, 0x20, 0x32, 0x2e, 0x38, 0x31, 0x2d, 0x32, 0x2e, 0x33, 0x38, 0x34, 0x61, 0x34, 0x38, 0x2e, 0x30, 0x34, 0x20, 0x34, 0x38, 0x2e, 0x30, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x32, 0x2e, 0x37, 0x33, 0x37, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x35, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x38, 0x36, 0x20, 0x31, 0x39, 0x34, 0x2e, 0x38, 0x36, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x36, 0x20, 0x33, 0x31, 0x2e, 0x36, 0x39, 0x36, 0x63, 0x31, 0x31, 0x2e, 0x38, 0x32, 0x38, 0x20, 0x34, 0x2e, 0x31, 0x33, 0x37, 0x20, 0x32, 0x34, 0x2e, 0x31, 0x35, 0x31, 0x20, 0x37, 0x2e, 0x32, 0x32, 0x35, 0x20, 0x33, 0x36, 0x2e, 0x38, 0x37, 0x38, 0x20, 0x39, 0x2e, 0x30, 0x36, 0x33, 0x20, 0x31, 0x2e, 0x32, 0x32, 0x20, 0x38, 0x2e, 0x34, 0x31, 0x37, 0x2e, 0x32, 0x34, 0x38, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x32, 0x32, 0x2d, 0x33, 0x2e, 0x30, 0x37, 0x32, 0x20, 0x32, 0x35, 0x2e, 0x31, 0x37, 0x31, 0x6c, 0x2d, 0x31, 0x2e, 0x34, 0x20, 0x33, 0x2e, 0x34, 0x31, 0x31, 0x20, 0x33, 0x2e, 0x36, 0x2e, 0x37, 0x39, 0x33, 0x63, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x32, 0x2e, 0x30, 0x32, 0x37, 0x20, 0x31, 0x38, 0x2e, 0x35, 0x32, 0x33, 0x20, 0x33, 0x2e, 0x30, 0x36, 0x20, 0x32, 0x37, 0x2e, 0x36, 0x33, 0x31, 0x20, 0x33, 0x2e, 0x30, 0x36, 0x6c, 0x32, 0x37, 0x2e, 0x36, 0x32, 0x33, 0x2d, 0x33, 0x2e, 0x30, 0x36, 0x20, 0x33, 0x2e, 0x36, 0x30, 0x34, 0x2d, 0x2e, 0x37, 0x39, 0x33, 0x2d, 0x31, 0x2e, 0x34, 0x30, 0x33, 0x2d, 0x33, 0x2e, 0x34, 0x31, 0x37, 0x63, 0x2d, 0x33, 0x2e, 0x33, 0x31, 0x32, 0x2d, 0x38, 0x2e, 0x30, 0x35, 0x2d, 0x34, 0x2e, 0x32, 0x38, 0x34, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x36, 0x35, 0x2d, 0x33, 0x2e, 0x30, 0x36, 0x33, 0x2d, 0x32, 0x35, 0x2e, 0x31, 0x38, 0x33, 0x20, 0x31, 0x32, 0x2e, 0x36, 0x37, 0x36, 0x2d, 0x31, 0x2e, 0x38, 0x34, 0x20, 0x32, 0x34, 0x2e, 0x39, 0x35, 0x34, 0x2d, 0x34, 0x2e, 0x39, 0x32, 0x20, 0x33, 0x36, 0x2e, 0x37, 0x33, 0x38, 0x2d, 0x39, 0x2e, 0x30, 0x34, 0x35, 0x61, 0x31, 0x39, 0x35, 0x2e, 0x31, 0x30, 0x38, 0x20, 0x31, 0x39, 0x35, 0x2e, 0x31, 0x30, 0x38, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x39, 0x2e, 0x34, 0x38, 0x32, 0x2d, 0x33, 0x31, 0x2e, 0x37, 0x32, 0x36, 0x20, 0x34, 0x38, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x34, 0x38, 0x2e, 0x32, 0x35, 0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x32, 0x2e, 0x38, 0x34, 0x38, 0x20, 0x31, 0x30, 0x2e, 0x36, 0x36, 0x6c, 0x32, 0x2e, 0x38, 0x30, 0x39, 0x20, 0x32, 0x2e, 0x33, 0x38, 0x20, 0x31, 0x2e, 0x38, 0x36, 0x32, 0x2d, 0x33, 0x2e, 0x31, 0x36, 0x38, 0x63, 0x39, 0x2e, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x32, 0x39, 0x37, 0x20, 0x31, 0x35, 0x2e, 0x33, 0x36, 0x38, 0x2d, 0x33, 0x33, 0x2e, 0x39, 0x36, 0x35, 0x20, 0x31, 0x37, 0x2e, 0x31, 0x34, 0x32, 0x2d, 0x35, 0x32, 0x2e, 0x35, 0x31, 0x33, 0x6c, 0x2e, 0x33, 0x34, 0x35, 0x2d, 0x33, 0x2e, 0x36, 0x36, 0x35, 0x2d, 0x33, 0x2e, 0x36, 0x31, 0x34, 0x2e, 0x32, 0x37, 0x39, 0x7a, 0x4d, 0x31, 0x36, 0x37, 0x2e, 0x34, 0x39, 0x20, 0x31, 0x37, 0x32, 0x2e, 0x39, 0x36, 0x63, 0x2d, 0x31, 0x33, 0x2e, 0x30, 0x36, 0x38, 0x20, 0x33, 0x2e, 0x35, 0x35, 0x34, 0x2d, 0x32, 0x36, 0x2e, 0x33, 0x34, 0x20, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x2d, 0x33, 0x39, 0x2e, 0x35, 0x33, 0x32, 0x20, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x2d, 0x31, 0x33, 0x2e, 0x32, 0x32, 0x38, 0x20, 0x30, 0x2d, 0x32, 0x36, 0x2e, 0x34, 0x38, 0x33, 0x2d, 0x31, 0x2e, 0x37, 0x39, 0x33, 0x2d, 0x33, 0x39, 0x2e, 0x35, 0x36, 0x33, 0x2d, 0x35, 0x2e, 0x33, 0x34, 0x38, 0x61, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x35, 0x35, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x35, 0x35, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x31, 0x36, 0x2e, 0x39, 0x33, 0x32, 0x2d, 0x33, 0x35, 0x2e, 0x36, 0x37, 0x63, 0x2d, 0x34, 0x2e, 0x30, 0x36, 0x36, 0x2d, 0x31, 0x32, 0x2e, 0x35, 0x31, 0x37, 0x2d, 0x36, 0x2e, 0x34, 0x34, 0x35, 0x2d, 0x32, 0x35, 0x2e, 0x36, 0x33, 0x2d, 0x37, 0x2e, 0x31, 0x33, 0x35, 0x2d, 0x33, 0x39, 0x2e, 0x31, 0x33, 0x34, 0x20, 0x38, 0x2e, 0x34, 0x34, 0x36, 0x2d, 0x31, 0x30, 0x2e, 0x34, 0x34, 0x33, 0x20, 0x31, 0x38, 0x2e, 0x30, 0x35, 0x32, 0x2d, 0x31, 0x39, 0x2e, 0x35, 0x39, 0x31, 0x20, 0x32, 0x38, 0x2e, 0x36, 0x36, 0x35, 0x2d, 0x32, 0x37, 0x2e, 0x32, 0x39, 0x33, 0x61, 0x31, 0x35, 0x32, 0x2e, 0x36, 0x32, 0x20, 0x31, 0x35, 0x32, 0x2e, 0x36, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x34, 0x2e, 0x39, 0x36, 0x35, 0x2d, 0x31, 0x39, 0x2e, 0x30, 0x31, 0x31, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x34, 0x32, 0x20, 0x31, 0x35, 0x33, 0x2e, 0x32, 0x34, 0x32, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x20, 0x33, 0x34, 0x2e, 0x38, 0x39, 0x38, 0x20, 0x31, 0x38, 0x2e, 0x39, 0x37, 0x63, 0x31, 0x30, 0x2e, 0x36, 0x35, 0x34, 0x20, 0x37, 0x2e, 0x37, 0x34, 0x33, 0x20, 0x32, 0x30, 0x2e, 0x33, 0x30, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x39, 0x36, 0x32, 0x20, 0x32, 0x38, 0x2e, 0x37, 0x39, 0x20, 0x32, 0x37, 0x2e, 0x34, 0x37, 0x2d, 0x2e, 0x37, 0x32, 0x34, 0x20, 0x31, 0x33, 0x2e, 0x34, 0x32, 0x37, 0x2d, 0x33, 0x2e, 0x31, 0x33, 0x32, 0x20, 0x32, 0x36, 0x2e, 0x34, 0x36, 0x35, 0x2d, 0x37, 0x2e, 0x32, 0x30, 0x34, 0x20, 0x33, 0x38, 0x2e, 0x39, 0x36, 0x31, 0x61, 0x31, 0x35, 0x32, 0x2e, 0x37, 0x36, 0x37, 0x20, 0x31, 0x35, 0x32, 0x2e, 0x37, 0x36, 0x37, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x2d, 0x31, 0x36, 0x2e, 0x39, 0x35, 0x32, 0x20, 0x33, 0x35, 0x2e, 0x37, 0x30, 0x37, 0x7a, 0x6d, 0x2d, 0x32, 0x38, 0x2e, 0x37, 0x34, 0x2d, 0x36, 0x32, 0x2e, 0x39, 0x39, 0x38, 0x63, 0x30, 0x20, 0x39, 0x2e, 0x32, 0x33, 0x32, 0x20, 0x37, 0x2e, 0x34, 0x38, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x32, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x39, 0x2e, 0x32, 0x31, 0x37, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x37, 0x2e, 0x34, 0x36, 0x36, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x31, 0x39, 0x36, 0x2d, 0x37, 0x2e, 0x34, 0x37, 0x33, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x2d, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x31, 0x20, 0x37, 0x2e, 0x34, 0x39, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x30, 0x31, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x32, 0x7a, 0x6d, 0x2d, 0x32, 0x31, 0x2e, 0x35, 0x37, 0x38, 0x20, 0x30, 0x63, 0x30, 0x20, 0x39, 0x2e, 0x32, 0x33, 0x32, 0x2d, 0x37, 0x2e, 0x34, 0x38, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x2d, 0x39, 0x2e, 0x32, 0x32, 0x36, 0x20, 0x30, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x35, 0x2d, 0x37, 0x2e, 0x34, 0x36, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x35, 0x2d, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x30, 0x2d, 0x39, 0x2e, 0x31, 0x39, 0x33, 0x20, 0x37, 0x2e, 0x34, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x39, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x36, 0x2d, 0x31, 0x36, 0x2e, 0x36, 0x38, 0x39, 0x20, 0x39, 0x2e, 0x32, 0x32, 0x20, 0x30, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x37, 0x2e, 0x34, 0x39, 0x36, 0x20, 0x31, 0x36, 0x2e, 0x37, 0x20, 0x31, 0x36, 0x2e, 0x36, 0x39, 0x7a, 0x22, 0x20, 0x66, 0x69, 0x6c, 0x6c, 0x3d, 0x22, 0x23, 0x34, 0x31, 0x39, 0x45, 0x44, 0x41, 0x22, 0x2f, 0x3e, 0x3c, 0x2f, 0x73, 0x76, 0x67, 0x3e, 0xa}, MediaType: "image/svg+xml"}, Description: "A message about etcd operator, a description of channels"}, + {Schema: "olm.package", Name: "", DefaultChannel: "", Icon: nil, Description: ""}, + }, + Bundles: []Bundle{ + { + Schema: "olm.bundle", + Name: "cockroachdb.v2.0.9", + Package: "cockroachdb", + Image: "quay.io/openshift-community-operators/cockroachdb:v2.0.9", + Properties: []property.Property{ + {Type: "olm.channel", Value: json.RawMessage(`{"name":"stable"}`)}, + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"cockroachdb","version":"2.0.9"}`)}, + }, + }, + { + Schema: "olm.bundle", + Name: "cockroachdb.v2.1.11", + Package: "cockroachdb", + Image: "quay.io/openshift-community-operators/cockroachdb:v2.1.11", + Properties: []property.Property{ + {Type: "olm.channel", Value: json.RawMessage(`{"name":"stable","replaces":"cockroachdb.v2.1.1"}`)}, + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"cockroachdb","version":"2.1.11"}`)}, + }, + }, + { + Schema: "olm.bundle", + Name: "cockroachdb.v2.1.1", + Package: "cockroachdb", + Image: "quay.io/openshift-community-operators/cockroachdb:v2.1.1", + Properties: []property.Property{ + {Type: "olm.channel", Value: json.RawMessage(`{"name":"stable","replaces":"cockroachdb.v2.0.9"}`)}, + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"cockroachdb","version":"2.1.1"}`)}, + }, + }, + { + Schema: "olm.bundle", + Name: "cockroachdb.v3.0.7", + Package: "cockroachdb", + Image: "quay.io/openshift-community-operators/cockroachdb:v3.0.7", + Properties: []property.Property{ + {Type: "olm.channel", Value: json.RawMessage(`{"name":"stable-3.x"}`)}, + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"cockroachdb","version":"3.0.7"}`)}, + }, + }, + { + Schema: "olm.bundle", + Name: "cockroachdb.v5.0.3", + Package: "cockroachdb", + Image: "quay.io/openshift-community-operators/cockroachdb:v5.0.3", + Properties: []property.Property{ + {Type: "olm.channel", Value: json.RawMessage(`{"name":"stable-5.x"}`)}, + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"cockroachdb","version":"5.0.3"}`)}, + }, + }, + { + Schema: "olm.bundle", + Name: "etcdoperator-community.v0.6.1", + Package: "etcd", + Image: "quay.io/operatorhubio/etcd:v0.6.1", + Properties: []property.Property{ + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"etcd","version":"0.6.1"}`)}, + {Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdCluster","version":"v1beta2"}`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"alpha"}`)}, + {Type: "olm.skipRange", Value: json.RawMessage(`"<0.6.1"`)}, + {Type: "olm.bundle.object", Value: json.RawMessage(fmt.Sprintf(`{"data": %q}`, base64.StdEncoding.EncodeToString(etcdCSV.Data)))}, + }, + RelatedImages: []RelatedImage{{Name: "etcdv0.6.1", Image: "quay.io/coreos/etcd-operator@sha256:bd944a211eaf8f31da5e6d69e8541e7cada8f16a9f7a5a570b22478997819943"}}, + Objects: []string{toJSON(t, etcdCSV.Data)}, + CsvJSON: toJSON(t, etcdCSV.Data), + }, + { + Schema: "olm.bundle", + Name: "etcdoperator.v0.9.0", + Package: "etcd", + Image: "quay.io/operatorhubio/etcd:v0.9.0", + Properties: []property.Property{ + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"etcd","version":"0.9.0"}`)}, + {Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdBackup","version":"v1beta2"}`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"singlenamespace-alpha"}`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"clusterwide-alpha"}`)}, + }, + RelatedImages: []RelatedImage{{Name: "etcdv0.9.0", Image: "quay.io/coreos/etcd-operator@sha256:db563baa8194fcfe39d1df744ed70024b0f1f9e9b55b5923c2f3a413c44dc6b8"}}, + }, + { + Schema: "olm.bundle", + Name: "etcdoperator.v0.9.2", + Package: "etcd", + Image: "quay.io/operatorhubio/etcd:v0.9.2", + Properties: []property.Property{ + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"etcd","version":"0.9.2"}`)}, + {Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdRestore","version":"v1beta2"}`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"singlenamespace-alpha","replaces":"etcdoperator.v0.9.0"}`)}, + }, + RelatedImages: []RelatedImage{{Name: "etcdv0.9.2", Image: "quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2"}}, + }, + { + Schema: "olm.bundle", + Name: "etcdoperator.v0.9.2-clusterwide", + Package: "etcd", + Image: "quay.io/operatorhubio/etcd:v0.9.2-clusterwide", + Properties: []property.Property{ + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"etcd","version":"0.9.2-clusterwide"}`)}, + {Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdBackup","version":"v1beta2"}`)}, + {Type: "olm.skipRange", Value: json.RawMessage(`">=0.9.0 <=0.9.1"`)}, + {Type: "olm.skips", Value: json.RawMessage(`"etcdoperator.v0.6.1"`)}, + {Type: "olm.skips", Value: json.RawMessage(`"etcdoperator.v0.9.0"`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"clusterwide-alpha","replaces":"etcdoperator.v0.9.0"}`)}, + }, + RelatedImages: []RelatedImage{{Name: "etcdv0.9.2", Image: "quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2"}}, + }, + { + Schema: "olm.bundle", + Name: "etcdoperator.v0.9.4", + Package: "etcd", + Image: "quay.io/operatorhubio/etcd:v0.9.4", + Properties: []property.Property{ + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"etcd","version":"0.9.4"}`)}, + {Type: "olm.package.required", Value: json.RawMessage(`{"packageName":"test","versionRange":">=1.2.3 <2.0.0-0"}`)}, + {Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdBackup","version":"v1beta2"}`)}, + {Type: "olm.gvk.required", Value: json.RawMessage(`{"group":"testapi.coreos.com","kind":"Testapi","version":"v1"}`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"singlenamespace-alpha","replaces":"etcdoperator.v0.9.2"}`)}, + }, + RelatedImages: []RelatedImage{{Name: "etcdv0.9.2", Image: "quay.io/coreos/etcd-operator@sha256:66a37fd61a06a43969854ee6d3e21087a98b93838e284a6086b13917f96b0d9b"}}, + }, + { + Schema: "olm.bundle", + Name: "etcdoperator.v0.9.4-clusterwide", + Package: "etcd", + Image: "quay.io/operatorhubio/etcd:v0.9.4-clusterwide", + Properties: []property.Property{ + {Type: "olm.package", Value: json.RawMessage(`{"packageName":"etcd","version":"0.9.4-clusterwide"}`)}, + {Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdBackup","version":"v1beta2"}`)}, + {Type: "olm.channel", Value: json.RawMessage(`{"name":"clusterwide-alpha","replaces":"etcdoperator.v0.9.2-clusterwide"}`)}, + }, + RelatedImages: []RelatedImage{{Name: "etcdv0.9.2", Image: "quay.io/coreos/etcd-operator@sha256:66a37fd61a06a43969854ee6d3e21087a98b93838e284a6086b13917f96b0d9b"}}, + }, + { + Schema: "olm.bundle", + }, + }, + Deprecations: []Deprecation{ + { + Schema: SchemaDeprecation, + Package: "kiali", + Entries: []DeprecationEntry{ + {Reference: PackageScopedReference{Schema: SchemaBundle, Name: "kiali-operator.v1.68.0"}, Message: "kiali-operator.v1.68.0 is deprecated. Uninstall and install kiali-operator.v1.72.0 for support.\n"}, + {Reference: PackageScopedReference{Schema: SchemaPackage}, Message: "package kiali is end of life. Please use 'kiali-new' package for support.\n"}, + {Reference: PackageScopedReference{Schema: SchemaChannel, Name: "alpha"}, Message: "channel alpha is no longer supported. Please switch to channel 'stable'.\n"}, + }, + }, + }, + Others: []Meta{ + {Schema: "unexpected", Package: "", Blob: json.RawMessage(`{ "schema": "unexpected" }`)}, + }, + }, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + cfg, err := LoadFS(context.Background(), s.fsys) + s.assertion(t, err) + if err == nil { + require.NotNil(t, cfg) + equalsDeclarativeConfig(t, *s.expected, *cfg) + } + }) + } +} + +func toJSON(t *testing.T, in []byte) string { + t.Helper() + out, err := yaml.ToJSON(in) + if err != nil { + t.Fatalf("failed converting testdata to JSON: %v", err) + } + return string(out) +} + +var ( + invalidBundle = &fstest.MapFile{ + Data: []byte(`{"schema": "olm.bundle","relatedImages": {}}`), + } + invalidPackage = &fstest.MapFile{ + Data: []byte(`{"schema": "olm.package","name": {}}`), + } + noSchema = &fstest.MapFile{ + Data: []byte(`hello: world`), + } + invalidFormat = &fstest.MapFile{ + Data: []byte(`[This is not yaml or json.}`), + } + notObject = &fstest.MapFile{ + Data: []byte(`[]`), + } + invalidFS = fstest.MapFS{ + "invalid-bundle.json": invalidBundle, + "invalid-package.json": invalidPackage, + "no-schema.yaml": noSchema, + "invalid-format.txt": invalidFormat, + "not-object.json": notObject, + } + + indexIgnore = &fstest.MapFile{ + Data: []byte(`* +!*.json +!*.yaml + +*.clusterserviceversion.yaml`), + } + cockroachdb = &fstest.MapFile{ + Data: []byte(`{ + "schema": "olm.package", + "name": "cockroachdb", + "defaultChannel": "stable-5.x", + "icon": { + "base64data": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMS44MiAzMiIgd2lkdGg9IjI0ODYiIGhlaWdodD0iMjUwMCI+PHRpdGxlPkNMPC90aXRsZT48cGF0aCBkPSJNMTkuNDIgOS4xN2ExNS4zOSAxNS4zOSAwIDAgMS0zLjUxLjQgMTUuNDYgMTUuNDYgMCAwIDEtMy41MS0uNCAxNS42MyAxNS42MyAwIDAgMSAzLjUxLTMuOTEgMTUuNzEgMTUuNzEgMCAwIDEgMy41MSAzLjkxek0zMCAuNTdBMTcuMjIgMTcuMjIgMCAwIDAgMjUuNTkgMGExNy40IDE3LjQgMCAwIDAtOS42OCAyLjkzQTE3LjM4IDE3LjM4IDAgMCAwIDYuMjMgMGExNy4yMiAxNy4yMiAwIDAgMC00LjQ0LjU3QTE2LjIyIDE2LjIyIDAgMCAwIDAgMS4xM2EuMDcuMDcgMCAwIDAgMCAuMDkgMTcuMzIgMTcuMzIgMCAwIDAgLjgzIDEuNTcuMDcuMDcgMCAwIDAgLjA4IDAgMTYuMzkgMTYuMzkgMCAwIDEgMS44MS0uNTQgMTUuNjUgMTUuNjUgMCAwIDEgMTEuNTkgMS44OCAxNy41MiAxNy41MiAwIDAgMC0zLjc4IDQuNDhjLS4yLjMyLS4zNy42NS0uNTUgMXMtLjIyLjQ1LS4zMy42OS0uMzEuNzItLjQ0IDEuMDhhMTcuNDYgMTcuNDYgMCAwIDAgNC4yOSAxOC43Yy4yNi4yNS41My40OS44MS43M3MuNDQuMzcuNjcuNTQuNTkuNDQuODkuNjRhLjA3LjA3IDAgMCAwIC4wOCAwYy4zLS4yMS42LS40Mi44OS0uNjRzLjQ1LS4zNS42Ny0uNTQuNTUtLjQ4LjgxLS43M2ExNy40NSAxNy40NSAwIDAgMCA1LjM4LTEyLjYxIDE3LjM5IDE3LjM5IDAgMCAwLTEuMDktNi4wOWMtLjE0LS4zNy0uMjktLjczLS40NS0xLjA5cy0uMjItLjQ3LS4zMy0uNjktLjM1LS42Ni0uNTUtMWExNy42MSAxNy42MSAwIDAgMC0zLjc4LTQuNDggMTUuNjUgMTUuNjUgMCAwIDEgMTEuNi0xLjg0IDE2LjEzIDE2LjEzIDAgMCAxIDEuODEuNTQuMDcuMDcgMCAwIDAgLjA4IDBxLjQ0LS43Ni44Mi0xLjU2YS4wNy4wNyAwIDAgMCAwLS4wOUExNi44OSAxNi44OSAwIDAgMCAzMCAuNTd6IiBmaWxsPSIjMTUxZjM0Ii8+PHBhdGggZD0iTTIxLjgyIDE3LjQ3YTE1LjUxIDE1LjUxIDAgMCAxLTQuMjUgMTAuNjkgMTUuNjYgMTUuNjYgMCAwIDEtLjcyLTQuNjggMTUuNSAxNS41IDAgMCAxIDQuMjUtMTAuNjkgMTUuNjIgMTUuNjIgMCAwIDEgLjcyIDQuNjgiIGZpbGw9IiMzNDg1NDAiLz48cGF0aCBkPSJNMTUgMjMuNDhhMTUuNTUgMTUuNTUgMCAwIDEtLjcyIDQuNjggMTUuNTQgMTUuNTQgMCAwIDEtMy41My0xNS4zN0ExNS41IDE1LjUgMCAwIDEgMTUgMjMuNDgiIGZpbGw9IiM3ZGJjNDIiLz48L3N2Zz4=", + "mediatype": "image/svg+xml" + } +} +{ + "schema": "olm.bundle", + "name": "cockroachdb.v2.0.9", + "package": "cockroachdb", + "image": "quay.io/openshift-community-operators/cockroachdb:v2.0.9", + "properties": [ + { + "type": "olm.channel", + "value": { + "name": "stable" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "cockroachdb", + "version": "2.0.9" + } + } + ] +} +{ + "schema": "olm.bundle", + "name": "cockroachdb.v2.1.11", + "package": "cockroachdb", + "image": "quay.io/openshift-community-operators/cockroachdb:v2.1.11", + "properties": [ + { + "type": "olm.channel", + "value": { + "name": "stable", + "replaces": "cockroachdb.v2.1.1" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "cockroachdb", + "version": "2.1.11" + } + } + ] +} +{ + "schema": "olm.bundle", + "name": "cockroachdb.v2.1.1", + "package": "cockroachdb", + "image": "quay.io/openshift-community-operators/cockroachdb:v2.1.1", + "properties": [ + { + "type": "olm.channel", + "value": { + "name": "stable", + "replaces": "cockroachdb.v2.0.9" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "cockroachdb", + "version": "2.1.1" + } + } + ] +} +{ + "schema": "olm.bundle", + "name": "cockroachdb.v3.0.7", + "package": "cockroachdb", + "image": "quay.io/openshift-community-operators/cockroachdb:v3.0.7", + "properties": [ + { + "type": "olm.channel", + "value": { + "name": "stable-3.x" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "cockroachdb", + "version": "3.0.7" + } + } + ] +} +{ + "schema": "olm.bundle", + "name": "cockroachdb.v5.0.3", + "package": "cockroachdb", + "image": "quay.io/openshift-community-operators/cockroachdb:v5.0.3", + "properties": [ + { + "type": "olm.channel", + "value": { + "name": "stable-5.x" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "cockroachdb", + "version": "5.0.3" + } + } + ] +}`), + } + etcd = &fstest.MapFile{ + Data: []byte(fmt.Sprintf(`--- +schema: olm.package +name: etcd +defaultChannel: singlenamespace-alpha +description: A message about etcd operator, a description of channels +icon: + base64data: PHN2ZyB3aWR0aD0iMjUwMCIgaGVpZ2h0PSIyNDIyIiB2aWV3Qm94PSIwIDAgMjU2IDI0OCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTI1Mi4zODYgMTI4LjA2NGMtMS4yMDIuMS0yLjQxLjE0Ny0zLjY5My4xNDctNy40NDYgMC0xNC42Ny0xLjc0Ni0yMS4xODctNC45NDQgMi4xNy0xMi40NDcgMy4wOTItMjQuOTg3IDIuODUtMzcuNDgxLTcuMDY1LTEwLjIyLTE1LjE0LTE5Ljg2My0yNC4yNTYtMjguNzQ3IDMuOTU1LTcuNDE1IDkuODAxLTEzLjc5NSAxNy4xLTE4LjMxOWwzLjEzMy0xLjkzNy0yLjQ0Mi0yLjc1NGMtMTIuNTgxLTE0LjE2Ny0yNy41OTYtMjUuMTItNDQuNjItMzIuNTUyTDE3NS44NzYgMGwtLjg2MiAzLjU4OGMtMi4wMyA4LjM2My02LjI3NCAxNS45MDgtMTIuMSAyMS45NjJhMTkzLjg0MiAxOTMuODQyIDAgMCAwLTM0Ljk1Ni0xNC40MDVBMTk0LjAxMiAxOTQuMDEyIDAgMCAwIDkzLjA1NiAyNS41MkM4Ny4yNTQgMTkuNDczIDgzLjAyIDExLjk0NyA4MC45OTkgMy42MDhMODAuMTMuMDJsLTMuMzgyIDEuNDdDNTkuOTM5IDguODE1IDQ0LjUxIDIwLjA2NSAzMi4xMzUgMzQuMDJsLTIuNDQ5IDIuNzYgMy4xMyAxLjkzN2M3LjI3NiA0LjUwNiAxMy4xMDYgMTAuODQ5IDE3LjA1NCAxOC4yMjMtOS4wODggOC44NS0xNy4xNTQgMTguNDYyLTI0LjIxNCAyOC42MzUtLjI3NSAxMi40ODkuNiAyNS4xMiAyLjc4IDM3Ljc0LTYuNDg0IDMuMTY3LTEzLjY2OCA0Ljg5NC0yMS4wNjUgNC44OTQtMS4yOTggMC0yLjUxMy0uMDQ3LTMuNjkzLS4xNDVMMCAxMjcuNzg1bC4zNDUgMy42NzFjMS44MDIgMTguNTc4IDcuNTcgMzYuMjQ3IDE3LjE1NCA1Mi41MjNsMS44NyAzLjE3NiAyLjgxLTIuMzg0YTQ4LjA0IDQ4LjA0IDAgMCAxIDIyLjczNy0xMC42NSAxOTQuODYgMTk0Ljg2IDAgMCAwIDE5LjQ2IDMxLjY5NmMxMS44MjggNC4xMzcgMjQuMTUxIDcuMjI1IDM2Ljg3OCA5LjA2MyAxLjIyIDguNDE3LjI0OCAxNy4xMjItMy4wNzIgMjUuMTcxbC0xLjQgMy40MTEgMy42Ljc5M2M5LjIyIDIuMDI3IDE4LjUyMyAzLjA2IDI3LjYzMSAzLjA2bDI3LjYyMy0zLjA2IDMuNjA0LS43OTMtMS40MDMtMy40MTdjLTMuMzEyLTguMDUtNC4yODQtMTYuNzY1LTMuMDYzLTI1LjE4MyAxMi42NzYtMS44NCAyNC45NTQtNC45MiAzNi43MzgtOS4wNDVhMTk1LjEwOCAxOTUuMTA4IDAgMCAwIDE5LjQ4Mi0zMS43MjYgNDguMjU0IDQ4LjI1NCAwIDAgMSAyMi44NDggMTAuNjZsMi44MDkgMi4zOCAxLjg2Mi0zLjE2OGM5LjYtMTYuMjk3IDE1LjM2OC0zMy45NjUgMTcuMTQyLTUyLjUxM2wuMzQ1LTMuNjY1LTMuNjE0LjI3OXpNMTY3LjQ5IDE3Mi45NmMtMTMuMDY4IDMuNTU0LTI2LjM0IDUuMzQ4LTM5LjUzMiA1LjM0OC0xMy4yMjggMC0yNi40ODMtMS43OTMtMzkuNTYzLTUuMzQ4YTE1My4yNTUgMTUzLjI1NSAwIDAgMS0xNi45MzItMzUuNjdjLTQuMDY2LTEyLjUxNy02LjQ0NS0yNS42My03LjEzNS0zOS4xMzQgOC40NDYtMTAuNDQzIDE4LjA1Mi0xOS41OTEgMjguNjY1LTI3LjI5M2ExNTIuNjIgMTUyLjYyIDAgMCAxIDM0Ljk2NS0xOS4wMTEgMTUzLjI0MiAxNTMuMjQyIDAgMCAxIDM0Ljg5OCAxOC45N2MxMC42NTQgNy43NDMgMjAuMzAyIDE2Ljk2MiAyOC43OSAyNy40Ny0uNzI0IDEzLjQyNy0zLjEzMiAyNi40NjUtNy4yMDQgMzguOTYxYTE1Mi43NjcgMTUyLjc2NyAwIDAgMS0xNi45NTIgMzUuNzA3em0tMjguNzQtNjIuOTk4YzAgOS4yMzIgNy40ODIgMTYuNyAxNi43MDIgMTYuNyA5LjIxNyAwIDE2LjY5LTcuNDY2IDE2LjY5LTE2LjcgMC05LjE5Ni03LjQ3My0xNi42OTItMTYuNjktMTYuNjkyLTkuMjIgMC0xNi43MDEgNy40OTYtMTYuNzAxIDE2LjY5MnptLTIxLjU3OCAwYzAgOS4yMzItNy40OCAxNi43LTE2LjcgMTYuNy05LjIyNiAwLTE2LjY4NS03LjQ2Ni0xNi42ODUtMTYuNyAwLTkuMTkzIDcuNDYtMTYuNjg5IDE2LjY4Ni0xNi42ODkgOS4yMiAwIDE2LjcgNy40OTYgMTYuNyAxNi42OXoiIGZpbGw9IiM0MTlFREEiLz48L3N2Zz4K + mediatype: image/svg+xml + +--- +schema: olm.bundle +package: etcd +name: etcdoperator-community.v0.6.1 +image: quay.io/operatorhubio/etcd:v0.6.1 +properties: + - type: olm.package + value: + packageName: etcd + version: 0.6.1 + - type: olm.gvk + value: + group: etcd.database.coreos.com + kind: EtcdCluster + version: v1beta2 + - type: olm.channel + value: + name: alpha + - type: olm.skipRange + value: <0.6.1 + - type: olm.bundle.object + value: + data: %q +relatedImages: + - image: quay.io/coreos/etcd-operator@sha256:bd944a211eaf8f31da5e6d69e8541e7cada8f16a9f7a5a570b22478997819943 + name: etcdv0.6.1 + +--- +schema: olm.bundle +package: etcd +name: etcdoperator.v0.9.0 +image: quay.io/operatorhubio/etcd:v0.9.0 +properties: + - type: olm.package + value: + packageName: etcd + version: 0.9.0 + - type: olm.gvk + value: + group: etcd.database.coreos.com + kind: EtcdBackup + version: v1beta2 + - type: olm.channel + value: + name: singlenamespace-alpha + - type: olm.channel + value: + name: clusterwide-alpha +relatedImages: + - image: quay.io/coreos/etcd-operator@sha256:db563baa8194fcfe39d1df744ed70024b0f1f9e9b55b5923c2f3a413c44dc6b8 + name: etcdv0.9.0 + +--- +schema: olm.bundle +package: etcd +name: etcdoperator.v0.9.2 +image: quay.io/operatorhubio/etcd:v0.9.2 +properties: + - type: olm.package + value: + packageName: etcd + version: 0.9.2 + - type: olm.gvk + value: + group: etcd.database.coreos.com + kind: EtcdRestore + version: v1beta2 + - type: olm.channel + value: + name: singlenamespace-alpha + replaces: etcdoperator.v0.9.0 +relatedImages: + - image: quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2 + name: etcdv0.9.2 + +--- +schema: olm.bundle +package: etcd +name: etcdoperator.v0.9.2-clusterwide +image: quay.io/operatorhubio/etcd:v0.9.2-clusterwide +properties: + - type: olm.package + value: + packageName: etcd + version: 0.9.2-clusterwide + - type: olm.gvk + value: + group: etcd.database.coreos.com + kind: EtcdBackup + version: v1beta2 + - type: olm.skipRange + value: '>=0.9.0 <=0.9.1' + - type: olm.skips + value: etcdoperator.v0.6.1 + - type: olm.skips + value: etcdoperator.v0.9.0 + - type: olm.channel + value: + name: clusterwide-alpha + replaces: etcdoperator.v0.9.0 +relatedImages: + - image: quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2 + name: etcdv0.9.2 + +--- +schema: olm.bundle +package: etcd +name: etcdoperator.v0.9.4 +image: quay.io/operatorhubio/etcd:v0.9.4 +properties: + - type: olm.package + value: + packageName: etcd + version: 0.9.4 + - type: olm.package.required + value: + packageName: test + versionRange: '>=1.2.3 <2.0.0-0' + - type: olm.gvk + value: + group: etcd.database.coreos.com + kind: EtcdBackup + version: v1beta2 + - type: olm.gvk.required + value: + group: testapi.coreos.com + kind: Testapi + version: v1 + - type: olm.channel + value: + name: singlenamespace-alpha + replaces: etcdoperator.v0.9.2 +relatedImages: + - image: quay.io/coreos/etcd-operator@sha256:66a37fd61a06a43969854ee6d3e21087a98b93838e284a6086b13917f96b0d9b + name: etcdv0.9.2 + +--- +schema: olm.bundle +package: etcd +name: etcdoperator.v0.9.4-clusterwide +image: quay.io/operatorhubio/etcd:v0.9.4-clusterwide +properties: + - type: olm.package + value: + packageName: etcd + version: 0.9.4-clusterwide + - type: olm.gvk + value: + group: etcd.database.coreos.com + kind: EtcdBackup + version: v1beta2 + - type: olm.channel + value: + name: clusterwide-alpha + replaces: etcdoperator.v0.9.2-clusterwide +relatedImages: + - image: quay.io/coreos/etcd-operator@sha256:66a37fd61a06a43969854ee6d3e21087a98b93838e284a6086b13917f96b0d9b + name: etcdv0.9.2`, base64.StdEncoding.EncodeToString(etcdCSV.Data))), + } + etcdCSV = &fstest.MapFile{ + Data: []byte(`apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + capabilities: Full Lifecycle + description: etcd is a distributed key value store providing a reliable way to + store data across a cluster of machines. + tectonic-visibility: ocs + name: etcdoperator.v0.6.1 + namespace: placeholder +spec: + customresourcedefinitions: + owned: + - description: Represents a cluster of etcd nodes. + displayName: etcd Cluster + kind: EtcdCluster + name: etcdclusters.etcd.database.coreos.com + resources: + - kind: Service + version: v1 + - kind: Pod + version: v1 + specDescriptors: + - description: The desired number of member Pods for the etcd cluster. + displayName: Size + path: size + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podCount + statusDescriptors: + - description: The status of each of the member Pods for the etcd cluster. + displayName: Member Status + path: members + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podStatuses + - description: The service at which the running etcd cluster can be accessed. + displayName: Service + path: service + x-descriptors: + - urn:alm:descriptor:io.kubernetes:Service + - description: The current size of the etcd cluster. + displayName: Cluster Size + path: size + - description: The current version of the etcd cluster. + displayName: Current Version + path: currentVersion + - description: The target version of the etcd cluster, after upgrading. + displayName: Target Version + path: targetVersion + - description: The current status of the etcd cluster. + displayName: Status + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + - description: Explanation for the current status of the cluster. + displayName: Status Details + path: reason + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase:reason + version: v1beta2 + description: "etcd is a distributed key value store that provides a reliable way\ + \ to store data across a cluster of machines. It\xE2\u20AC\u2122s open-source\ + \ and available on GitHub. etcd gracefully handles leader elections during network\ + \ partitions and will tolerate machine failure, including the leader. Your applications\ + \ can read and write data into etcd.\nA simple use-case is to store database connection\ + \ details or feature flags within etcd as key value pairs. These values can be\ + \ watched, allowing your app to reconfigure itself when they change. Advanced\ + \ uses take advantage of the consistency guarantees to implement database leader\ + \ elections or do distributed locking across a cluster of workers.\n\n_The etcd\ + \ Open Cloud Service is Public Alpha. The goal before Beta is to fully implement\ + \ backup features._\n\n### Reading and writing to etcd\n\nCommunicate with etcd\ + \ though its command line utility ` + "`etcdctl`" + ` or with the API using the automatically\ + \ generated Kubernetes Service.\n\n[Read the complete guide to using the etcd\ + \ Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\n\ + \n### Supported Features\n**High availability**\nMultiple instances of etcd are\ + \ networked together and secured. Individual failures or networking issues are\ + \ transparently handled to keep your cluster up and running.\n**Automated updates**\n\ + Rolling out a new etcd version works like all Kubernetes rolling updates. Simply\ + \ declare the desired version, and the etcd service starts a safe rolling update\ + \ to the new version automatically.\n**Backups included**\nComing soon, the ability\ + \ to schedule backups to happen on or off cluster.\n" + displayName: etcd + icon: + - base64data: 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 + mediatype: image/png + install: + spec: + deployments: + - name: etcd-operator + spec: + replicas: 1 + selector: + matchLabels: + name: etcd-operator-alm-owned + template: + metadata: + labels: + name: etcd-operator-alm-owned + name: etcd-operator-alm-owned + spec: + containers: + - command: + - etcd-operator + - --create-crd=false + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + image: quay.io/coreos/etcd-operator@sha256:bd944a211eaf8f31da5e6d69e8541e7cada8f16a9f7a5a570b22478997819943 + name: etcd-operator + serviceAccountName: etcd-operator + permissions: + - rules: + - apiGroups: + - etcd.database.coreos.com + resources: + - etcdclusters + verbs: + - '*' + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - '*' + - apiGroups: + - '' + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + verbs: + - '*' + - apiGroups: + - apps + resources: + - deployments + verbs: + - '*' + - apiGroups: + - '' + resources: + - secrets + verbs: + - get + serviceAccountName: etcd-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - etcd + - key value + - database + - coreos + - open source + labels: + alm-owner-etcd: etcdoperator + alm-status-descriptors: etcdoperator.v0.6.1 + operated-by: etcdoperator + links: + - name: Blog + url: https://coreos.com/etcd + - name: Documentation + url: https://coreos.com/operators/etcd/docs/latest/ + - name: etcd Operator Source Code + url: https://github.com/coreos/etcd-operator + maintainers: + - email: support@coreos.com + name: CoreOS, Inc + maturity: alpha + provider: + name: CoreOS, Inc + selector: + matchLabels: + alm-owner-etcd: etcdoperator + operated-by: etcdoperator + version: 0.6.1 +`), + } + readme = &fstest.MapFile{ + Data: []byte(`# Valid Declarative Config + +This is a README file about this declarative config. It should be ignored +when loading this directory as declarative config due to the patterns +present in the .indexignore file.`), + } + unrecognizedSchema = &fstest.MapFile{ + Data: []byte(`{"schema":"olm.package"}{"schema":"unexpected"}{"schema":"olm.bundle"}`), + } + deprecations = &fstest.MapFile{ + Data: []byte(`--- +schema: olm.deprecations +package: kiali +entries: +- reference: + schema: olm.bundle + name: kiali-operator.v1.68.0 + message: | + kiali-operator.v1.68.0 is deprecated. Uninstall and install kiali-operator.v1.72.0 for support. +- reference: + schema: olm.package + message: | + package kiali is end of life. Please use 'kiali-new' package for support. +- reference: + schema: olm.channel + name: alpha + message: | + channel alpha is no longer supported. Please switch to channel 'stable'.`), + } + + validFS = fstest.MapFS{ + ".indexignore": indexIgnore, + "cockroachdb.json": cockroachdb, + "etcd.yaml": etcd, + "etcdoperator.v0.6.1.clusterserviceversion.yaml": etcdCSV, + "README.md": readme, + "unrecognized-schema.json": unrecognizedSchema, + "deprecations.yaml": deprecations, + } +) + +type EvaluationFunc func(*testing.T, *DeclarativeConfig) + +func TestLoadFile(t *testing.T) { + type spec struct { + name string + fsys fs.FS + path string + assertion require.ErrorAssertionFunc + expect EvaluationFunc + } + specs := []spec{ + { + name: "Error/NonExistentDir", + fsys: os.DirFS("non/existent/dir/"), + assertion: require.Error, + }, + { + name: "Error/Invalid", + fsys: invalidFS, + assertion: require.Error, + }, + { + name: "Error/NotYAMLOrJSON", + fsys: invalidFS, + path: "invalid-format.txt", + assertion: require.Error, + }, + { + name: "Error/NotJSONObject", + fsys: invalidFS, + path: "not-object.json", + assertion: require.Error, + }, + { + name: "Error/NoSchema", + fsys: invalidFS, + path: "no-schema.yaml", + assertion: require.Error, + }, + { + name: "Error/InvalidPackageJSON", + fsys: invalidFS, + path: "invalid-package.json", + assertion: require.Error, + }, + { + name: "Error/InvalidBundleJSON", + fsys: invalidFS, + path: "invalid-bundle.json", + assertion: require.Error, + }, + { + name: "Success/UnrecognizedSchema", + fsys: validFS, + path: "unrecognized-schema.json", + assertion: require.NoError, + expect: func(t *testing.T, d *DeclarativeConfig) { + require.Len(t, d.Packages, 1) + require.Len(t, d.Bundles, 1) + require.Len(t, d.Others, 1) + }, + }, + { + name: "Success/ValidFile", + fsys: validFS, + path: "etcd.yaml", + assertion: require.NoError, + expect: func(t *testing.T, d *DeclarativeConfig) { + require.Len(t, d.Packages, 1) + require.Len(t, d.Bundles, 6) + require.Empty(t, d.Others) + }, + }, + { + name: "Success/ValidFile/Deprecations", + fsys: validFS, + path: "deprecations.yaml", + assertion: require.NoError, + expect: func(t *testing.T, d *DeclarativeConfig) { + require.Empty(t, d.Packages) + require.Empty(t, d.Bundles) + require.Empty(t, d.Others) + require.Len(t, d.Deprecations, 1) + }, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + cfg, err := LoadFile(s.fsys, s.path) + s.assertion(t, err) + if err == nil { + require.NotNil(t, cfg) + s.expect(t, cfg) + } + }) + } +} diff --git a/alpha/declcfg/model_to_declcfg.go b/alpha/declcfg/model_to_declcfg.go new file mode 100644 index 000000000..fabb0d0d2 --- /dev/null +++ b/alpha/declcfg/model_to_declcfg.go @@ -0,0 +1,133 @@ +package declcfg + +import ( + "sort" + + "github.com/operator-framework/operator-registry/alpha/model" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func ConvertFromModel(mpkgs model.Model) DeclarativeConfig { + cfg := DeclarativeConfig{} + for _, mpkg := range mpkgs { + channels, bundles := traverseModelChannels(*mpkg) + + var i *Icon + if mpkg.Icon != nil { + i = &Icon{ + Data: mpkg.Icon.Data, + MediaType: mpkg.Icon.MediaType, + } + } + defaultChannel := "" + if mpkg.DefaultChannel != nil { + defaultChannel = mpkg.DefaultChannel.Name + } + cfg.Packages = append(cfg.Packages, Package{ + Schema: SchemaPackage, + Name: mpkg.Name, + DefaultChannel: defaultChannel, + Icon: i, + Description: mpkg.Description, + }) + cfg.Channels = append(cfg.Channels, channels...) + cfg.Bundles = append(cfg.Bundles, bundles...) + } + + sort.Slice(cfg.Packages, func(i, j int) bool { + return cfg.Packages[i].Name < cfg.Packages[j].Name + }) + sort.Slice(cfg.Channels, func(i, j int) bool { + if cfg.Channels[i].Package != cfg.Channels[j].Package { + return cfg.Channels[i].Package < cfg.Channels[j].Package + } + return cfg.Channels[i].Name < cfg.Channels[j].Name + }) + sort.Slice(cfg.Bundles, func(i, j int) bool { + if cfg.Bundles[i].Package != cfg.Bundles[j].Package { + return cfg.Bundles[i].Package < cfg.Bundles[j].Package + } + return cfg.Bundles[i].Name < cfg.Bundles[j].Name + }) + + return cfg +} + +func traverseModelChannels(mpkg model.Package) ([]Channel, []Bundle) { + channels := []Channel{} + bundleMap := map[string]*Bundle{} + + for _, ch := range mpkg.Channels { + // initialize channel + c := Channel{ + Schema: SchemaChannel, + Name: ch.Name, + Package: ch.Package.Name, + Entries: []ChannelEntry{}, + // NOTICE: The field Properties of the type Channel is for internal use only. + // DO NOT use it for any public-facing functionalities. + // This API is in alpha stage and it is subject to change. + Properties: ch.Properties, + } + + for _, chb := range ch.Bundles { + // populate channel entry + c.Entries = append(c.Entries, ChannelEntry{ + Name: chb.Name, + Replaces: chb.Replaces, + Skips: chb.Skips, + SkipRange: chb.SkipRange, + }) + + // create or update bundle + b, ok := bundleMap[chb.Name] + if !ok { + b = &Bundle{ + Schema: SchemaBundle, + Name: chb.Name, + Package: chb.Package.Name, + Image: chb.Image, + RelatedImages: ModelRelatedImagesToRelatedImages(chb.RelatedImages), + CsvJSON: chb.CsvJSON, + Objects: chb.Objects, + } + bundleMap[b.Name] = b + } + b.Properties = append(b.Properties, chb.Properties...) + } + + // sort channel entries by name + sort.Slice(c.Entries, func(i, j int) bool { + return c.Entries[i].Name < c.Entries[j].Name + }) + channels = append(channels, c) + } + + // nolint:prealloc + var bundles []Bundle + for _, b := range bundleMap { + b.Properties = property.Deduplicate(b.Properties) + + sort.Slice(b.Properties, func(i, j int) bool { + if b.Properties[i].Type != b.Properties[j].Type { + return b.Properties[i].Type < b.Properties[j].Type + } + return string(b.Properties[i].Value) < string(b.Properties[j].Value) + }) + + bundles = append(bundles, *b) + } + return channels, bundles +} + +func ModelRelatedImagesToRelatedImages(relatedImages []model.RelatedImage) []RelatedImage { + // nolint:prealloc + var out []RelatedImage + for _, ri := range relatedImages { + out = append(out, RelatedImage{ + Name: ri.Name, + Image: ri.Image, + }) + } + return out +} diff --git a/alpha/declcfg/model_to_declcfg_test.go b/alpha/declcfg/model_to_declcfg_test.go new file mode 100644 index 000000000..07fe7d577 --- /dev/null +++ b/alpha/declcfg/model_to_declcfg_test.go @@ -0,0 +1,39 @@ +package declcfg + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/model" +) + +func TestConvertFromModel(t *testing.T) { + type spec struct { + name string + m model.Model + expectCfg DeclarativeConfig + } + + specs := []spec{ + { + name: "Success", + m: buildTestModel(), + expectCfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: false, IncludeDeprecations: false}), + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + s.m.Normalize() + require.NoError(t, s.m.Validate()) + actual := ConvertFromModel(s.m) + + removeJSONWhitespace(&s.expectCfg) + removeJSONWhitespace(&actual) + + assert.Equal(t, s.expectCfg, actual) + }) + } +} diff --git a/alpha/declcfg/write.go b/alpha/declcfg/write.go new file mode 100644 index 000000000..293d9363b --- /dev/null +++ b/alpha/declcfg/write.go @@ -0,0 +1,544 @@ +package declcfg + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/blang/semver/v4" + "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/yaml" + + "github.com/operator-framework/operator-registry/alpha/property" +) + +type MermaidWriter struct { + MinEdgeName string + SpecifiedPackageName string +} + +type MermaidOption func(*MermaidWriter) + +func NewMermaidWriter(opts ...MermaidOption) *MermaidWriter { + const ( + minEdgeName = "" + specifiedPackageName = "" + ) + m := &MermaidWriter{ + MinEdgeName: minEdgeName, + SpecifiedPackageName: specifiedPackageName, + } + + for _, opt := range opts { + opt(m) + } + return m +} + +func WithMinEdgeName(minEdgeName string) MermaidOption { + return func(o *MermaidWriter) { + o.MinEdgeName = minEdgeName + } +} + +func WithSpecifiedPackageName(specifiedPackageName string) MermaidOption { + return func(o *MermaidWriter) { + o.SpecifiedPackageName = specifiedPackageName + } +} + +// writes out the channel edges of the declarative config graph in a mermaid format capable of being pasted into +// mermaid renderers like github, mermaid.live, etc. +// output is sorted lexicographically by package name, and then by channel name +// if provided, minEdgeName will be used as the lower bound for edges in the output graph +// +// Example output: +// graph LR +// +// %% package "neuvector-certified-operator-rhmp" +// subgraph "neuvector-certified-operator-rhmp" +// %% channel "beta" +// subgraph neuvector-certified-operator-rhmp-beta["beta"] +// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.8["neuvector-operator.v1.2.8"] +// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.9["neuvector-operator.v1.2.9"] +// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"] +// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]-- replaces --> neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.8["neuvector-operator.v1.2.8"] +// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]-- skips --> neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.9["neuvector-operator.v1.2.9"] +// end +// end +// +// end +func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer) error { + pkgs := map[string]*strings.Builder{} + + sort.Slice(cfg.Channels, func(i, j int) bool { + return cfg.Channels[i].Name < cfg.Channels[j].Name + }) + + versionMap, err := getBundleVersions(&cfg) + if err != nil { + return err + } + + // establish a 'floor' version, either specified by user or entirely open + minVersion := semver.Version{Major: 0, Minor: 0, Patch: 0} + + if writer.MinEdgeName != "" { + if _, ok := versionMap[writer.MinEdgeName]; !ok { + return fmt.Errorf("unknown minimum edge name: %q", writer.MinEdgeName) + } + minVersion = versionMap[writer.MinEdgeName] + } + + // build increasing-version-ordered bundle names, so we can meaningfully iterate over a range + orderedBundles := []string{} + for n := range versionMap { + orderedBundles = append(orderedBundles, n) + } + sort.Slice(orderedBundles, func(i, j int) bool { + return versionMap[orderedBundles[i]].LT(versionMap[orderedBundles[j]]) + }) + + minEdgePackage := writer.getMinEdgePackage(&cfg) + + depByPackage := sets.Set[string]{} + depByChannel := sets.Set[string]{} + depByBundle := sets.Set[string]{} + + for _, d := range cfg.Deprecations { + for _, e := range d.Entries { + switch e.Reference.Schema { + case SchemaPackage: + depByPackage.Insert(d.Package) + case SchemaChannel: + depByChannel.Insert(e.Reference.Name) + case SchemaBundle: + depByBundle.Insert(e.Reference.Name) + } + } + } + + var deprecatedPackage string + deprecatedChannels := []string{} + + for _, c := range cfg.Channels { + filteredChannel := writer.filterChannel(&c, versionMap, minVersion, minEdgePackage) + // nolint:nestif + if filteredChannel != nil { + pkgBuilder, ok := pkgs[c.Package] + if !ok { + pkgBuilder = &strings.Builder{} + pkgs[c.Package] = pkgBuilder + } + + channelID := fmt.Sprintf("%s-%s", filteredChannel.Package, filteredChannel.Name) + pkgBuilder.WriteString(fmt.Sprintf(" %%%% channel %q\n", filteredChannel.Name)) + pkgBuilder.WriteString(fmt.Sprintf(" subgraph %s[%q]\n", channelID, filteredChannel.Name)) + + if depByPackage.Has(filteredChannel.Package) { + deprecatedPackage = filteredChannel.Package + } + + if depByChannel.Has(filteredChannel.Name) { + deprecatedChannels = append(deprecatedChannels, channelID) + } + + for _, ce := range filteredChannel.Entries { + if versionMap[ce.Name].GE(minVersion) { + bundleDeprecation := "" + if depByBundle.Has(ce.Name) { + bundleDeprecation = ":::deprecated" + } + + entryID := fmt.Sprintf("%s-%s", channelID, ce.Name) + pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]%s\n", entryID, ce.Name, bundleDeprecation)) + + if len(ce.Replaces) > 0 { + replacesID := fmt.Sprintf("%s-%s", channelID, ce.Replaces) + pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]-- %s --> %s[%q]\n", replacesID, ce.Replaces, "replace", entryID, ce.Name)) + } + if len(ce.Skips) > 0 { + for _, s := range ce.Skips { + skipsID := fmt.Sprintf("%s-%s", channelID, s) + pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]-- %s --> %s[%q]\n", skipsID, s, "skip", entryID, ce.Name)) + } + } + if len(ce.SkipRange) > 0 { + skipRange, err := semver.ParseRange(ce.SkipRange) + if err == nil { + for _, edgeName := range filteredChannel.Entries { + if skipRange(versionMap[edgeName.Name]) { + skipRangeID := fmt.Sprintf("%s-%s", channelID, edgeName.Name) + pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]-- \"%s(%s)\" --> %s[%q]\n", skipRangeID, edgeName.Name, "skipRange", ce.SkipRange, entryID, ce.Name)) + } + } + } else { + fmt.Fprintf(os.Stderr, "warning: ignoring invalid SkipRange for package/edge %q/%q: %v\n", c.Package, ce.Name, err) + } + } + } + } + pkgBuilder.WriteString(" end\n") + } + } + + _, _ = out.Write([]byte("graph LR\n")) + _, _ = out.Write([]byte(" classDef deprecated fill:#E8960F\n")) + pkgNames := []string{} + for pname := range pkgs { + pkgNames = append(pkgNames, pname) + } + sort.Slice(pkgNames, func(i, j int) bool { + return pkgNames[i] < pkgNames[j] + }) + for _, pkgName := range pkgNames { + _, _ = out.Write([]byte(fmt.Sprintf(" %%%% package %q\n", pkgName))) + _, _ = out.Write([]byte(fmt.Sprintf(" subgraph %q\n", pkgName))) + _, _ = out.Write([]byte(pkgs[pkgName].String())) + _, _ = out.Write([]byte(" end\n")) + } + + if deprecatedPackage != "" { + _, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#989695\n", deprecatedPackage))) + } + + if len(deprecatedChannels) > 0 { + for _, deprecatedChannel := range deprecatedChannels { + _, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#DCD0FF\n", deprecatedChannel))) + } + } + + return nil +} + +// filters the channel edges to include only those which are greater-than-or-equal to the edge named by startVersion +// returns a nil channel if all edges are filtered out +func (writer *MermaidWriter) filterChannel(c *Channel, versionMap map[string]semver.Version, minVersion semver.Version, minEdgePackage string) *Channel { + // short-circuit if no active filters + if writer.MinEdgeName == "" && writer.SpecifiedPackageName == "" { + return c + } + + // short-circuit if channel's package doesn't match filter + if writer.SpecifiedPackageName != "" && c.Package != writer.SpecifiedPackageName { + return nil + } + + // short-circuit if channel package is mismatch from filter + if minEdgePackage != "" && c.Package != minEdgePackage { + return nil + } + + out := &Channel{Name: c.Name, Package: c.Package, Properties: c.Properties, Entries: []ChannelEntry{}} + for _, ce := range c.Entries { + filteredCe := ChannelEntry{Name: ce.Name} + // nolint:nestif + if writer.MinEdgeName == "" { + // no minimum-edge specified + filteredCe.SkipRange = ce.SkipRange + filteredCe.Replaces = ce.Replaces + filteredCe.Skips = append(filteredCe.Skips, ce.Skips...) + + // accumulate IFF there are any relevant skips/skipRange/replaces remaining or there never were any to begin with + // for the case where all skip/skipRange/replaces are retained, this is effectively the original edge with validated linkages + if len(filteredCe.Replaces) > 0 || len(filteredCe.Skips) > 0 || len(filteredCe.SkipRange) > 0 { + out.Entries = append(out.Entries, filteredCe) + } else { + if len(ce.Replaces) == 0 && len(ce.SkipRange) == 0 && len(ce.Skips) == 0 { + out.Entries = append(out.Entries, filteredCe) + } + } + } else { + if ce.Name == writer.MinEdgeName { + // edge is the 'floor', meaning that since all references are "backward references", and we don't want any references from this edge + // accumulate w/o references + out.Entries = append(out.Entries, filteredCe) + } else { + // edge needs to be filtered to determine if it is below the floor (bad) or on/above (good) + if len(ce.Replaces) > 0 && versionMap[ce.Replaces].GTE(minVersion) { + filteredCe.Replaces = ce.Replaces + } + if len(ce.Skips) > 0 { + filteredSkips := []string{} + for _, s := range ce.Skips { + if versionMap[s].GTE(minVersion) { + filteredSkips = append(filteredSkips, s) + } + } + if len(filteredSkips) > 0 { + filteredCe.Skips = filteredSkips + } + } + if len(ce.SkipRange) > 0 { + skipRange, err := semver.ParseRange(ce.SkipRange) + // if skipRange can't be parsed, just don't filter based on it + if err == nil && skipRange(minVersion) { + // specified range includes our floor + filteredCe.SkipRange = ce.SkipRange + } + } + // accumulate IFF there are any relevant skips/skipRange/replaces remaining, or there never were any to begin with (NOP) + // but the edge name satisfies the minimum-edge constraint + // for the case where all skip/skipRange/replaces are retained, this is effectively `ce` but with validated linkages + if len(filteredCe.Replaces) > 0 || len(filteredCe.Skips) > 0 || len(filteredCe.SkipRange) > 0 { + out.Entries = append(out.Entries, filteredCe) + } else { + if len(ce.Replaces) == 0 && len(ce.SkipRange) == 0 && len(ce.Skips) == 0 && versionMap[filteredCe.Name].GTE(minVersion) { + out.Entries = append(out.Entries, filteredCe) + } + } + } + } + } + + if len(out.Entries) > 0 { + return out + } else { + return nil + } +} + +func parseVersionProperty(b *Bundle) (*semver.Version, error) { + props, err := property.Parse(b.Properties) + if err != nil { + return nil, fmt.Errorf("parse properties for bundle %q: %v", b.Name, err) + } + if len(props.Packages) != 1 { + return nil, fmt.Errorf("bundle %q has multiple %q properties, expected exactly 1", b.Name, property.TypePackage) + } + v, err := semver.Parse(props.Packages[0].Version) + if err != nil { + return nil, fmt.Errorf("bundle %q has invalid version %q: %v", b.Name, props.Packages[0].Version, err) + } + + return &v, nil +} + +func getBundleVersions(cfg *DeclarativeConfig) (map[string]semver.Version, error) { + entries := make(map[string]semver.Version) + for index := range cfg.Bundles { + if _, ok := entries[cfg.Bundles[index].Name]; !ok { + ver, err := parseVersionProperty(&cfg.Bundles[index]) + if err != nil { + return entries, err + } + entries[cfg.Bundles[index].Name] = *ver + } + } + + return entries, nil +} + +func (writer *MermaidWriter) getMinEdgePackage(cfg *DeclarativeConfig) string { + if writer.MinEdgeName == "" { + return "" + } + + for _, c := range cfg.Channels { + for _, ce := range c.Entries { + if writer.MinEdgeName == ce.Name { + return c.Package + } + } + } + + return "" +} + +func WriteJSON(cfg DeclarativeConfig, w io.Writer) error { + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + enc.SetEscapeHTML(false) + return writeToEncoder(cfg, enc) +} + +func WriteYAML(cfg DeclarativeConfig, w io.Writer) error { + enc := newYAMLEncoder(w) + enc.SetEscapeHTML(false) + return writeToEncoder(cfg, enc) +} + +type yamlEncoder struct { + w io.Writer + escapeHTML bool +} + +func newYAMLEncoder(w io.Writer) *yamlEncoder { + return &yamlEncoder{w, true} +} + +func (e *yamlEncoder) SetEscapeHTML(on bool) { + e.escapeHTML = on +} + +func (e *yamlEncoder) Encode(v interface{}) error { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + enc.SetEscapeHTML(e.escapeHTML) + if err := enc.Encode(v); err != nil { + return err + } + yamlData, err := yaml.JSONToYAML(buf.Bytes()) + if err != nil { + return err + } + yamlData = append([]byte("---\n"), yamlData...) + _, err = e.w.Write(yamlData) + return err +} + +type encoder interface { + Encode(interface{}) error +} + +func writeToEncoder(cfg DeclarativeConfig, enc encoder) error { + pkgNames := sets.NewString() + + packagesByName := map[string][]Package{} + for _, p := range cfg.Packages { + pkgName := p.Name + pkgNames.Insert(pkgName) + packagesByName[pkgName] = append(packagesByName[pkgName], p) + } + channelsByPackage := map[string][]Channel{} + for _, c := range cfg.Channels { + pkgName := c.Package + pkgNames.Insert(pkgName) + channelsByPackage[pkgName] = append(channelsByPackage[pkgName], c) + } + bundlesByPackage := map[string][]Bundle{} + for _, b := range cfg.Bundles { + pkgName := b.Package + pkgNames.Insert(pkgName) + bundlesByPackage[pkgName] = append(bundlesByPackage[pkgName], b) + } + othersByPackage := map[string][]Meta{} + for _, o := range cfg.Others { + pkgName := o.Package + pkgNames.Insert(pkgName) + othersByPackage[pkgName] = append(othersByPackage[pkgName], o) + } + deprecationsByPackage := map[string][]Deprecation{} + for _, d := range cfg.Deprecations { + pkgName := d.Package + pkgNames.Insert(pkgName) + deprecationsByPackage[pkgName] = append(deprecationsByPackage[pkgName], d) + } + + for _, pName := range pkgNames.List() { + if len(pName) == 0 { + continue + } + pkgs := packagesByName[pName] + for _, p := range pkgs { + if err := enc.Encode(p); err != nil { + return err + } + } + + channels := channelsByPackage[pName] + sort.Slice(channels, func(i, j int) bool { + return channels[i].Name < channels[j].Name + }) + for _, c := range channels { + if err := enc.Encode(c); err != nil { + return err + } + } + + bundles := bundlesByPackage[pName] + sort.Slice(bundles, func(i, j int) bool { + return bundles[i].Name < bundles[j].Name + }) + for _, b := range bundles { + if err := enc.Encode(b); err != nil { + return err + } + } + + others := othersByPackage[pName] + sort.SliceStable(others, func(i, j int) bool { + return others[i].Schema < others[j].Schema + }) + for _, o := range others { + if err := enc.Encode(o); err != nil { + return err + } + } + + // + // Normally we would order the deprecations, but it really doesn't make sense since + // - there will be 0 or 1 of them for any given package + // - they have no other useful field for ordering + // + // validation is typically via conversion to a model.Model and invoking model.Package.Validate() + // It's possible that a user of the object could create a slice containing more then 1 + // Deprecation object for a package, and it would bypass validation if this + // function gets called without conversion. + // + deprecations := deprecationsByPackage[pName] + for _, d := range deprecations { + if err := enc.Encode(d); err != nil { + return err + } + } + } + + for _, o := range othersByPackage[""] { + if err := enc.Encode(o); err != nil { + return err + } + } + + return nil +} + +type WriteFunc func(config DeclarativeConfig, w io.Writer) error + +func WriteFS(cfg DeclarativeConfig, rootDir string, writeFunc WriteFunc, fileExt string) error { + channelsByPackage := map[string][]Channel{} + for _, c := range cfg.Channels { + channelsByPackage[c.Package] = append(channelsByPackage[c.Package], c) + } + bundlesByPackage := map[string][]Bundle{} + for _, b := range cfg.Bundles { + bundlesByPackage[b.Package] = append(bundlesByPackage[b.Package], b) + } + + if err := os.MkdirAll(rootDir, 0777); err != nil { + return err + } + + for _, p := range cfg.Packages { + fcfg := DeclarativeConfig{ + Packages: []Package{p}, + Channels: channelsByPackage[p.Name], + Bundles: bundlesByPackage[p.Name], + } + pkgDir := filepath.Join(rootDir, p.Name) + if err := os.MkdirAll(pkgDir, 0777); err != nil { + return err + } + filename := filepath.Join(pkgDir, fmt.Sprintf("catalog%s", fileExt)) + if err := writeFile(fcfg, filename, writeFunc); err != nil { + return err + } + } + return nil +} + +func writeFile(cfg DeclarativeConfig, filename string, writeFunc WriteFunc) error { + buf := &bytes.Buffer{} + if err := writeFunc(cfg, buf); err != nil { + return fmt.Errorf("write to buffer for %q: %v", filename, err) + } + if err := os.WriteFile(filename, buf.Bytes(), 0600); err != nil { + return fmt.Errorf("write file %q: %v", filename, err) + } + return nil +} diff --git a/alpha/declcfg/write_test.go b/alpha/declcfg/write_test.go new file mode 100644 index 000000000..eca428768 --- /dev/null +++ b/alpha/declcfg/write_test.go @@ -0,0 +1,613 @@ +package declcfg + +import ( + "bytes" + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWriteJSON(t *testing.T) { + type spec struct { + name string + cfg DeclarativeConfig + expected string + } + specs := []spec{ + { + name: "Success", + cfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}), + expected: `{ + "schema": "olm.package", + "name": "anakin", + "defaultChannel": "dark", + "icon": { + "base64data": "PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PGNpcmNsZSBjeD0iMjUiIGN5PSIyNSIgcj0iMjUiLz48L3N2Zz4=", + "mediatype": "image/svg+xml" + }, + "description": "anakin operator" +} +{ + "schema": "olm.channel", + "name": "dark", + "package": "anakin", + "entries": [ + { + "name": "anakin.v0.0.1" + }, + { + "name": "anakin.v0.1.0", + "replaces": "anakin.v0.0.1" + }, + { + "name": "anakin.v0.1.1", + "replaces": "anakin.v0.0.1", + "skips": [ + "anakin.v0.1.0" + ] + } + ] +} +{ + "schema": "olm.channel", + "name": "light", + "package": "anakin", + "entries": [ + { + "name": "anakin.v0.0.1" + }, + { + "name": "anakin.v0.1.0", + "replaces": "anakin.v0.0.1" + } + ] +} +{ + "schema": "olm.bundle", + "name": "anakin.v0.0.1", + "package": "anakin", + "image": "anakin-bundle:v0.0.1", + "properties": [ + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + } + }, + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMC4xIn19" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "anakin", + "version": "0.0.1" + } + } + ], + "relatedImages": [ + { + "name": "bundle", + "image": "anakin-bundle:v0.0.1" + } + ] +} +{ + "schema": "olm.bundle", + "name": "anakin.v0.1.0", + "package": "anakin", + "image": "anakin-bundle:v0.1.0", + "properties": [ + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + } + }, + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4wIn19" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "anakin", + "version": "0.1.0" + } + } + ], + "relatedImages": [ + { + "name": "bundle", + "image": "anakin-bundle:v0.1.0" + } + ] +} +{ + "schema": "olm.bundle", + "name": "anakin.v0.1.1", + "package": "anakin", + "image": "anakin-bundle:v0.1.1", + "properties": [ + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + } + }, + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4xIn19" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "anakin", + "version": "0.1.1" + } + } + ], + "relatedImages": [ + { + "name": "bundle", + "image": "anakin-bundle:v0.1.1" + } + ] +} +{ + "myField": "foobar", + "package": "anakin", + "schema": "custom.3" +} +{ + "schema": "olm.deprecations", + "package": "anakin", + "entries": [ + { + "reference": { + "schema": "olm.bundle", + "name": "anakin.v0.0.1" + }, + "message": "This bundle version is deprecated" + }, + { + "reference": { + "schema": "olm.channel", + "name": "light" + }, + "message": "This channel is deprecated" + }, + { + "reference": { + "schema": "olm.package" + }, + "message": "This package is deprecated... there is another" + } + ] +} +{ + "schema": "olm.package", + "name": "boba-fett", + "defaultChannel": "mando", + "icon": { + "base64data": "PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iNTAiLz48L3N2Zz4=", + "mediatype": "image/svg+xml" + }, + "description": "boba-fett operator" +} +{ + "schema": "olm.channel", + "name": "mando", + "package": "boba-fett", + "entries": [ + { + "name": "boba-fett.v1.0.0" + }, + { + "name": "boba-fett.v2.0.0", + "replaces": "boba-fett.v1.0.0" + } + ] +} +{ + "schema": "olm.bundle", + "name": "boba-fett.v1.0.0", + "package": "boba-fett", + "image": "boba-fett-bundle:v1.0.0", + "properties": [ + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + } + }, + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjEuMC4wIn19" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "boba-fett", + "version": "1.0.0" + } + } + ], + "relatedImages": [ + { + "name": "bundle", + "image": "boba-fett-bundle:v1.0.0" + } + ] +} +{ + "schema": "olm.bundle", + "name": "boba-fett.v2.0.0", + "package": "boba-fett", + "image": "boba-fett-bundle:v2.0.0", + "properties": [ + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=" + } + }, + { + "type": "olm.bundle.object", + "value": { + "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjIuMC4wIn19" + } + }, + { + "type": "olm.package", + "value": { + "packageName": "boba-fett", + "version": "2.0.0" + } + } + ], + "relatedImages": [ + { + "name": "bundle", + "image": "boba-fett-bundle:v2.0.0" + } + ] +} +{ + "myField": "foobar", + "package": "boba-fett", + "schema": "custom.3" +} +{ + "schema": "custom.1" +} +{ + "schema": "custom.2" +} +`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + var buf bytes.Buffer + err := WriteJSON(s.cfg, &buf) + require.NoError(t, err) + require.Equal(t, s.expected, buf.String()) + }) + } +} + +func TestWriteYAML(t *testing.T) { + type spec struct { + name string + cfg DeclarativeConfig + expected string + } + specs := []spec{ + { + name: "Success", + cfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}), + expected: `--- +defaultChannel: dark +description: anakin operator +icon: + base64data: PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PGNpcmNsZSBjeD0iMjUiIGN5PSIyNSIgcj0iMjUiLz48L3N2Zz4= + mediatype: image/svg+xml +name: anakin +schema: olm.package +--- +entries: +- name: anakin.v0.0.1 +- name: anakin.v0.1.0 + replaces: anakin.v0.0.1 +- name: anakin.v0.1.1 + replaces: anakin.v0.0.1 + skips: + - anakin.v0.1.0 +name: dark +package: anakin +schema: olm.channel +--- +entries: +- name: anakin.v0.0.1 +- name: anakin.v0.1.0 + replaces: anakin.v0.0.1 +name: light +package: anakin +schema: olm.channel +--- +image: anakin-bundle:v0.0.1 +name: anakin.v0.0.1 +package: anakin +properties: +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMC4xIn19 +- type: olm.package + value: + packageName: anakin + version: 0.0.1 +relatedImages: +- image: anakin-bundle:v0.0.1 + name: bundle +schema: olm.bundle +--- +image: anakin-bundle:v0.1.0 +name: anakin.v0.1.0 +package: anakin +properties: +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4wIn19 +- type: olm.package + value: + packageName: anakin + version: 0.1.0 +relatedImages: +- image: anakin-bundle:v0.1.0 + name: bundle +schema: olm.bundle +--- +image: anakin-bundle:v0.1.1 +name: anakin.v0.1.1 +package: anakin +properties: +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4xIn19 +- type: olm.package + value: + packageName: anakin + version: 0.1.1 +relatedImages: +- image: anakin-bundle:v0.1.1 + name: bundle +schema: olm.bundle +--- +myField: foobar +package: anakin +schema: custom.3 +--- +entries: +- message: This bundle version is deprecated + reference: + name: anakin.v0.0.1 + schema: olm.bundle +- message: This channel is deprecated + reference: + name: light + schema: olm.channel +- message: This package is deprecated... there is another + reference: + schema: olm.package +package: anakin +schema: olm.deprecations +--- +defaultChannel: mando +description: boba-fett operator +icon: + base64data: PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iNTAiLz48L3N2Zz4= + mediatype: image/svg+xml +name: boba-fett +schema: olm.package +--- +entries: +- name: boba-fett.v1.0.0 +- name: boba-fett.v2.0.0 + replaces: boba-fett.v1.0.0 +name: mando +package: boba-fett +schema: olm.channel +--- +image: boba-fett-bundle:v1.0.0 +name: boba-fett.v1.0.0 +package: boba-fett +properties: +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjEuMC4wIn19 +- type: olm.package + value: + packageName: boba-fett + version: 1.0.0 +relatedImages: +- image: boba-fett-bundle:v1.0.0 + name: bundle +schema: olm.bundle +--- +image: boba-fett-bundle:v2.0.0 +name: boba-fett.v2.0.0 +package: boba-fett +properties: +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0= +- type: olm.bundle.object + value: + data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjIuMC4wIn19 +- type: olm.package + value: + packageName: boba-fett + version: 2.0.0 +relatedImages: +- image: boba-fett-bundle:v2.0.0 + name: bundle +schema: olm.bundle +--- +myField: foobar +package: boba-fett +schema: custom.3 +--- +schema: custom.1 +--- +schema: custom.2 +`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + var buf bytes.Buffer + err := WriteYAML(s.cfg, &buf) + require.NoError(t, err) + require.Equal(t, s.expected, buf.String()) + }) + } +} + +func removeJSONWhitespace(cfg *DeclarativeConfig) { + for ib := range cfg.Bundles { + for ip := range cfg.Bundles[ib].Properties { + var buf bytes.Buffer + _ = json.Compact(&buf, cfg.Bundles[ib].Properties[ip].Value) + cfg.Bundles[ib].Properties[ip].Value = buf.Bytes() + } + } + for io := range cfg.Others { + var buf bytes.Buffer + _ = json.Compact(&buf, cfg.Others[io].Blob) + cfg.Others[io].Blob = buf.Bytes() + } +} + +func TestWriteMermaidChannels(t *testing.T) { + type spec struct { + name string + cfg DeclarativeConfig + startEdge string + packageFilter string + expected string + } + specs := []spec{ + { + name: "SuccessNoFilters", + cfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}), + startEdge: "", + packageFilter: "", + expected: `graph LR + classDef deprecated fill:#E8960F + %% package "anakin" + subgraph "anakin" + %% channel "dark" + subgraph anakin-dark["dark"] + anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated + anakin-dark-anakin.v0.1.0["anakin.v0.1.0"] + anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"] + anakin-dark-anakin.v0.1.1["anakin.v0.1.1"] + anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"] + anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"] + end + %% channel "light" + subgraph anakin-light["light"] + anakin-light-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated + anakin-light-anakin.v0.1.0["anakin.v0.1.0"] + anakin-light-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-light-anakin.v0.1.0["anakin.v0.1.0"] + end + end + %% package "boba-fett" + subgraph "boba-fett" + %% channel "mando" + subgraph boba-fett-mando["mando"] + boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"] + boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"] + boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"] + end + end +style anakin fill:#989695 +style anakin-light fill:#DCD0FF +`, + }, + { + name: "SuccessMinEdgeFilter", + cfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}), + startEdge: "anakin.v0.1.0", + packageFilter: "", + expected: `graph LR + classDef deprecated fill:#E8960F + %% package "anakin" + subgraph "anakin" + %% channel "dark" + subgraph anakin-dark["dark"] + anakin-dark-anakin.v0.1.0["anakin.v0.1.0"] + anakin-dark-anakin.v0.1.1["anakin.v0.1.1"] + anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"] + end + %% channel "light" + subgraph anakin-light["light"] + anakin-light-anakin.v0.1.0["anakin.v0.1.0"] + end + end +style anakin fill:#989695 +style anakin-light fill:#DCD0FF +`, + }, + { + name: "SuccessPackageNameFilter", + cfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}), + startEdge: "", + packageFilter: "boba-fett", + expected: `graph LR + classDef deprecated fill:#E8960F + %% package "boba-fett" + subgraph "boba-fett" + %% channel "mando" + subgraph boba-fett-mando["mando"] + boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"] + boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"] + boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"] + end + end +`, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + var buf bytes.Buffer + writer := NewMermaidWriter(WithMinEdgeName(s.startEdge), WithSpecifiedPackageName(s.packageFilter)) + err := writer.WriteChannels(s.cfg, &buf) + require.NoError(t, err) + require.Equal(t, s.expected, buf.String()) + }) + } +} diff --git a/alpha/doc.go b/alpha/doc.go new file mode 100644 index 000000000..e22855b2d --- /dev/null +++ b/alpha/doc.go @@ -0,0 +1,9 @@ +// Package alpha contains subpackages that have unstable Go APIs. +// Subpackages that achieve maturity will be deprecated and moved +// to other modules or packages within operator-registry. +// +// Presence in the alpha package should not be construed as being +// of less quality than non-alpha packages. Subpackages in the +// alpha package have the same standard for testing as all other +// packages in this repository. +package alpha diff --git a/alpha/model/error.go b/alpha/model/error.go new file mode 100644 index 000000000..e99cb2ca8 --- /dev/null +++ b/alpha/model/error.go @@ -0,0 +1,69 @@ +package model + +import ( + "bytes" + "errors" + "fmt" + "strings" +) + +type validationError struct { + message string + subErrors []error +} + +func newValidationError(message string) *validationError { + return &validationError{message: message} +} + +func (v *validationError) orNil() error { + if len(v.subErrors) == 0 { + return nil + } + return v +} + +func (v *validationError) Error() string { + if v == nil { + return "" + } + return strings.TrimSpace(v.errorPrefix(nil, true, nil)) +} + +func (v *validationError) errorPrefix(prefix []rune, last bool, seen []error) string { + for _, s := range seen { + if errors.Is(v, s) { + return "" + } + } + seen = append(seen, v) + sep := ":\n" + if len(v.subErrors) == 0 { + sep = "\n" + } + errMsg := bytes.NewBufferString(fmt.Sprintf("%s%s%s", string(prefix), v.message, sep)) + for i, serr := range v.subErrors { + subPrefix := prefix + if len(subPrefix) >= 4 { + if last { + subPrefix = append(subPrefix[0:len(subPrefix)-4], []rune(" ")...) + } else { + subPrefix = append(subPrefix[0:len(subPrefix)-4], []rune("│ ")...) + } + } + subLast := i == len(v.subErrors)-1 + if subLast { + subPrefix = append(subPrefix, []rune("└── ")...) + } else { + subPrefix = append(subPrefix, []rune("├── ")...) + } + + var verr *validationError + if errors.As(serr, &verr) { + errMsg.WriteString(verr.errorPrefix(subPrefix, subLast, seen)) + } else { + errMsg.WriteString(fmt.Sprintf("%s%s\n", string(subPrefix), serr)) + } + } + return errMsg.String() +} diff --git a/alpha/model/error_test.go b/alpha/model/error_test.go new file mode 100644 index 000000000..3f53aefd0 --- /dev/null +++ b/alpha/model/error_test.go @@ -0,0 +1,129 @@ +package model + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidationError_Error(t *testing.T) { + type spec struct { + name string + err *validationError + expect string + } + + recursiveErr := &validationError{ + message: "l1", + } + recursiveErr.subErrors = []error{ + fmt.Errorf("err1"), + &validationError{ + message: "l2", + subErrors: []error{ + fmt.Errorf("err3"), + recursiveErr, + fmt.Errorf("err4"), + }, + }, + fmt.Errorf("err2"), + } + + specs := []spec{ + { + name: "Nil", + err: nil, + expect: "", + }, + { + name: "Empty", + err: &validationError{}, + expect: "", + }, + { + name: "RecursiveError", + err: recursiveErr, + expect: `l1: +├── err1 +├── l2: +│ ├── err3 +│ └── err4 +└── err2`, + }, + { + name: "MessageOnly", + err: &validationError{message: "hello"}, + expect: "hello", + }, + { + name: "WithSubErrors", + err: &validationError{ + message: "hello", + subErrors: []error{ + fmt.Errorf("world"), + fmt.Errorf("foobar"), + }}, + expect: `hello: +├── world +└── foobar`, + }, + { + name: "WithEmptyLeafSubErrors", + err: &validationError{ + message: "hello", + subErrors: []error{ + &validationError{ + message: "foo", + subErrors: []error{}, + }, + &validationError{ + message: "bar", + subErrors: []error{ + fmt.Errorf("bar1"), + fmt.Errorf("bar2"), + }, + }, + }}, + expect: `hello: +├── foo +└── bar: + ├── bar1 + └── bar2`, + }, + { + name: "WithSubSubErrors", + err: &validationError{ + message: "hello", + subErrors: []error{ + &validationError{ + message: "foo", + subErrors: []error{ + fmt.Errorf("foo1"), + fmt.Errorf("foo2"), + }, + }, + &validationError{ + message: "bar", + subErrors: []error{ + fmt.Errorf("bar1"), + fmt.Errorf("bar2"), + }, + }, + }}, + expect: `hello: +├── foo: +│ ├── foo1 +│ └── foo2 +└── bar: + ├── bar1 + └── bar2`, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + require.Equal(t, s.expect, s.err.Error()) + }) + } +} diff --git a/alpha/model/model.go b/alpha/model/model.go new file mode 100644 index 000000000..9b4e3ae85 --- /dev/null +++ b/alpha/model/model.go @@ -0,0 +1,443 @@ +package model + +import ( + "errors" + "fmt" + "sort" + "strings" + + "github.com/blang/semver/v4" + "github.com/h2non/filetype" + "github.com/h2non/filetype/matchers" + "github.com/h2non/filetype/types" + svg "github.com/h2non/go-is-svg" + "golang.org/x/exp/maps" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/operator-framework/operator-registry/alpha/property" +) + +type Deprecation struct { + Message string `json:"message"` +} + +func init() { + t := types.NewType("svg", "image/svg+xml") + filetype.AddMatcher(t, svg.Is) + matchers.Image[types.NewType("svg", "image/svg+xml")] = svg.Is +} + +type Model map[string]*Package + +func (m Model) Validate() error { + result := newValidationError("invalid index") + + for name, pkg := range m { + if name != pkg.Name { + result.subErrors = append(result.subErrors, fmt.Errorf("package key %q does not match package name %q", name, pkg.Name)) + } + if err := pkg.Validate(); err != nil { + result.subErrors = append(result.subErrors, err) + } + } + return result.orNil() +} + +type Package struct { + Name string + Description string + Icon *Icon + DefaultChannel *Channel + Channels map[string]*Channel + Deprecation *Deprecation +} + +func (m *Package) Validate() error { + result := newValidationError(fmt.Sprintf("invalid package %q", m.Name)) + + if m.Name == "" { + result.subErrors = append(result.subErrors, errors.New("package name must not be empty")) + } + + if err := m.Icon.Validate(); err != nil { + result.subErrors = append(result.subErrors, err) + } + + if m.DefaultChannel == nil { + result.subErrors = append(result.subErrors, fmt.Errorf("default channel must be set")) + } + + if len(m.Channels) == 0 { + result.subErrors = append(result.subErrors, fmt.Errorf("package must contain at least one channel")) + } + + foundDefault := false + for name, ch := range m.Channels { + if name != ch.Name { + result.subErrors = append(result.subErrors, fmt.Errorf("channel key %q does not match channel name %q", name, ch.Name)) + } + if err := ch.Validate(); err != nil { + result.subErrors = append(result.subErrors, err) + } + if ch == m.DefaultChannel { + foundDefault = true + } + if ch.Package != m { + result.subErrors = append(result.subErrors, fmt.Errorf("channel %q not correctly linked to parent package", ch.Name)) + } + } + + if err := m.validateUniqueBundleVersions(); err != nil { + result.subErrors = append(result.subErrors, err) + } + + if m.DefaultChannel != nil && !foundDefault { + result.subErrors = append(result.subErrors, fmt.Errorf("default channel %q not found in channels list", m.DefaultChannel.Name)) + } + + if err := m.Deprecation.Validate(); err != nil { + result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err)) + } + + return result.orNil() +} + +func (m *Package) validateUniqueBundleVersions() error { + versionsMap := map[string]semver.Version{} + bundlesWithVersion := map[string]sets.Set[string]{} + for _, ch := range m.Channels { + for _, b := range ch.Bundles { + versionsMap[b.Version.String()] = b.Version + if bundlesWithVersion[b.Version.String()] == nil { + bundlesWithVersion[b.Version.String()] = sets.New[string]() + } + bundlesWithVersion[b.Version.String()].Insert(b.Name) + } + } + + versionsSlice := maps.Values(versionsMap) + semver.Sort(versionsSlice) + + var errs []error + for _, v := range versionsSlice { + bundles := sets.List(bundlesWithVersion[v.String()]) + if len(bundles) > 1 { + errs = append(errs, fmt.Errorf("{%s: [%s]}", v, strings.Join(bundles, ", "))) + } + } + + if len(errs) > 0 { + return fmt.Errorf("duplicate versions found in bundles: %v", errs) + } + return nil +} + +type Icon struct { + Data []byte `json:"base64data"` + MediaType string `json:"mediatype"` +} + +func (i *Icon) Validate() error { + if i == nil { + return nil + } + // TODO(joelanford): Should we check that data and mediatype are set, + // and detect the media type of the data and compare it to the + // mediatype listed in the icon field? Currently, some production + // index databases are failing these tests, so leaving this + // commented out for now. + result := newValidationError("invalid icon") + //if len(i.Data) == 0 { + // result.subErrors = append(result.subErrors, errors.New("icon data must be set if icon is defined")) + //} + //if len(i.MediaType) == 0 { + // result.subErrors = append(result.subErrors, errors.New("icon mediatype must be set if icon is defined")) + //} + //if len(i.Data) > 0 { + // if err := i.validateData(); err != nil { + // result.subErrors = append(result.subErrors, err) + // } + //} + return result.orNil() +} + +// nolint:unused +func (i *Icon) validateData() error { + if !filetype.IsImage(i.Data) { + return errors.New("icon data is not an image") + } + t, err := filetype.Match(i.Data) + if err != nil { + return err + } + if t.MIME.Value != i.MediaType { + return fmt.Errorf("icon media type %q does not match detected media type %q", i.MediaType, t.MIME.Value) + } + return nil +} + +type Channel struct { + Package *Package + Name string + Bundles map[string]*Bundle + Deprecation *Deprecation + // NOTICE: The field Properties of the type Channel is for internal use only. + // DO NOT use it for any public-facing functionalities. + // This API is in alpha stage and it is subject to change. + Properties []property.Property +} + +// TODO(joelanford): This function determines the channel head by finding the bundle that has 0 +// +// incoming edges, based on replaces and skips. It also expects to find exactly one such bundle. +// Is this the correct algorithm? +func (c Channel) Head() (*Bundle, error) { + incoming := map[string]int{} + for _, b := range c.Bundles { + if b.Replaces != "" { + incoming[b.Replaces]++ + } + for _, skip := range b.Skips { + incoming[skip]++ + } + } + var heads []*Bundle + for _, b := range c.Bundles { + if _, ok := incoming[b.Name]; !ok { + heads = append(heads, b) + } + } + if len(heads) == 0 { + return nil, fmt.Errorf("no channel head found in graph") + } + if len(heads) > 1 { + var headNames []string + for _, head := range heads { + headNames = append(headNames, head.Name) + } + sort.Strings(headNames) + return nil, fmt.Errorf("multiple channel heads found in graph: %s", strings.Join(headNames, ", ")) + } + return heads[0], nil +} + +func (c *Channel) Validate() error { + result := newValidationError(fmt.Sprintf("invalid channel %q", c.Name)) + + if c.Name == "" { + result.subErrors = append(result.subErrors, errors.New("channel name must not be empty")) + } + + if c.Package == nil { + result.subErrors = append(result.subErrors, errors.New("package must be set")) + } + + if len(c.Bundles) == 0 { + result.subErrors = append(result.subErrors, fmt.Errorf("channel must contain at least one bundle")) + } + + if len(c.Bundles) > 0 { + if err := c.validateReplacesChain(); err != nil { + result.subErrors = append(result.subErrors, err) + } + } + + for name, b := range c.Bundles { + if name != b.Name { + result.subErrors = append(result.subErrors, fmt.Errorf("bundle key %q does not match bundle name %q", name, b.Name)) + } + if err := b.Validate(); err != nil { + result.subErrors = append(result.subErrors, err) + } + if b.Channel != c { + result.subErrors = append(result.subErrors, fmt.Errorf("bundle %q not correctly linked to parent channel", b.Name)) + } + } + + if err := c.Deprecation.Validate(); err != nil { + result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err)) + } + + return result.orNil() +} + +// validateReplacesChain checks the replaces chain of a channel. +// Specifically the following rules must be followed: +// 1. There must be exactly 1 channel head. +// 2. Beginning at the head, the replaces chain must reach all non-skipped entries. +// Non-skipped entries are defined as entries that are not skipped by any other entry in the channel. +// 3. There must be no cycles in the replaces chain. +// 4. The tail entry in the replaces chain is permitted to replace a non-existent entry. +func (c *Channel) validateReplacesChain() error { + head, err := c.Head() + if err != nil { + return err + } + + allBundles := sets.NewString() + skippedBundles := sets.NewString() + for _, b := range c.Bundles { + allBundles = allBundles.Insert(b.Name) + skippedBundles = skippedBundles.Insert(b.Skips...) + } + + chainFrom := map[string][]string{} + replacesChainFromHead := sets.NewString(head.Name) + cur := head + for cur != nil { + if _, ok := chainFrom[cur.Name]; !ok { + chainFrom[cur.Name] = []string{cur.Name} + } + for k := range chainFrom { + chainFrom[k] = append(chainFrom[k], cur.Replaces) + } + if replacesChainFromHead.Has(cur.Replaces) { + return fmt.Errorf("detected cycle in replaces chain of upgrade graph: %s", strings.Join(chainFrom[cur.Replaces], " -> ")) + } + replacesChainFromHead = replacesChainFromHead.Insert(cur.Replaces) + cur = c.Bundles[cur.Replaces] + } + + strandedBundles := allBundles.Difference(replacesChainFromHead).Difference(skippedBundles).List() + if len(strandedBundles) > 0 { + return fmt.Errorf("channel contains one or more stranded bundles: %s", strings.Join(strandedBundles, ", ")) + } + + return nil +} + +type Bundle struct { + Package *Package + Channel *Channel + Name string + Image string + Replaces string + Skips []string + SkipRange string + Properties []property.Property + RelatedImages []RelatedImage + Deprecation *Deprecation + + // These fields are present so that we can continue serving + // the GRPC API the way packageserver expects us to in a + // backwards-compatible way. + Objects []string + CsvJSON string + + // These fields are used to compare bundles in a diff. + PropertiesP *property.Properties + Version semver.Version +} + +func (b *Bundle) Validate() error { + result := newValidationError(fmt.Sprintf("invalid bundle %q", b.Name)) + + if b.Name == "" { + result.subErrors = append(result.subErrors, errors.New("name must be set")) + } + if b.Channel == nil { + result.subErrors = append(result.subErrors, errors.New("channel must be set")) + } + if b.Package == nil { + result.subErrors = append(result.subErrors, errors.New("package must be set")) + } + if b.Channel != nil && b.Package != nil && b.Package != b.Channel.Package { + result.subErrors = append(result.subErrors, errors.New("package does not match channel's package")) + } + props, err := property.Parse(b.Properties) + if err != nil { + result.subErrors = append(result.subErrors, err) + } + for i, skip := range b.Skips { + if skip == "" { + result.subErrors = append(result.subErrors, fmt.Errorf("skip[%d] is empty", i)) + } + } + // TODO(joelanford): Validate related images? It looks like some + // CSVs in production databases use incorrect fields ([name,value] + // instead of [name,image]), which results in empty image values. + // Example is in redhat-operators: 3scale-operator.v0.5.5 + //for i, relatedImage := range b.RelatedImages { + // if err := relatedImage.Validate(); err != nil { + // result.subErrors = append(result.subErrors, WithIndex(i, err)) + // } + //} + + if props != nil && len(props.Packages) != 1 { + result.subErrors = append(result.subErrors, fmt.Errorf("must be exactly one property with type %q", property.TypePackage)) + } + + if b.Image == "" && len(b.Objects) == 0 { + result.subErrors = append(result.subErrors, errors.New("bundle image must be set")) + } + + if err := b.Deprecation.Validate(); err != nil { + result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err)) + } + + return result.orNil() +} + +type RelatedImage struct { + Name string + Image string +} + +func (i RelatedImage) Validate() error { + result := newValidationError("invalid related image") + if i.Image == "" { + result.subErrors = append(result.subErrors, fmt.Errorf("image must be set")) + } + return result.orNil() +} + +func (m Model) Normalize() { + for _, pkg := range m { + for _, ch := range pkg.Channels { + for _, b := range ch.Bundles { + for i := range b.Properties { + // Ensure property value is encoded in a standard way. + if normalized, err := property.Build(&b.Properties[i]); err == nil { + b.Properties[i] = *normalized + } + } + } + } + } +} + +func (m Model) AddBundle(b Bundle) { + if _, present := m[b.Package.Name]; !present { + m[b.Package.Name] = b.Package + } + p := m[b.Package.Name] + b.Package = p + + if ch, ok := p.Channels[b.Channel.Name]; ok { + b.Channel = ch + ch.Bundles[b.Name] = &b + } else { + newCh := &Channel{ + Name: b.Channel.Name, + Package: p, + Bundles: make(map[string]*Bundle), + } + b.Channel = newCh + newCh.Bundles[b.Name] = &b + p.Channels[newCh.Name] = newCh + } + + if p.DefaultChannel == nil { + p.DefaultChannel = b.Channel + } +} + +func (d *Deprecation) Validate() error { + if d == nil { + return nil + } + if d.Message == "" { + return errors.New("message must be set") + } + return nil +} diff --git a/alpha/model/model_test.go b/alpha/model/model_test.go new file mode 100644 index 000000000..11391b74c --- /dev/null +++ b/alpha/model/model_test.go @@ -0,0 +1,763 @@ +package model + +import ( + "encoding/base64" + "encoding/json" + "errors" + "testing" + + "github.com/blang/semver/v4" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/property" +) + +type validator interface { + Validate() error +} + +const svgData = `PHN2ZyB2aWV3Qm94PTAgMCAxMDAgMTAwPjxjaXJjbGUgY3g9MjUgY3k9MjUgcj0yNS8+PC9zdmc+` +const pngData = `iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=` +const jpegData = `/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q==` + +func mustBase64Decode(in string) []byte { + out, err := base64.StdEncoding.DecodeString(in) + if err != nil { + panic(err) + } + return out +} + +func TestNormalize(t *testing.T) { + b := &Bundle{} + pkgs := Model{ + "anakin": { + Channels: map[string]*Channel{ + "alpha": { + Bundles: map[string]*Bundle{ + "anakin.v0.0.1": b, + }, + }, + }, + }, + } + t.Run("Success/IgnoreInvalid", func(t *testing.T) { + invalidJSON := json.RawMessage(`}`) + b.Properties = []property.Property{{Value: invalidJSON}} + pkgs.Normalize() + assert.Equal(t, invalidJSON, b.Properties[0].Value) + }) + + t.Run("Success/Unchanged", func(t *testing.T) { + unchanged := json.RawMessage(`{}`) + b.Properties = []property.Property{{Value: unchanged}} + pkgs.Normalize() + assert.Equal(t, unchanged, b.Properties[0].Value) + }) + + t.Run("Success/RemoveSpaces", func(t *testing.T) { + withWhitespace := json.RawMessage(` { + "foo": "bar" + + } `) + expected := json.RawMessage(`{"foo":"bar"}`) + b.Properties = []property.Property{{Value: withWhitespace}} + pkgs.Normalize() + assert.Equal(t, expected, b.Properties[0].Value) + }) +} + +func TestChannelHead(t *testing.T) { + type spec struct { + name string + ch Channel + head *Bundle + assertion require.ErrorAssertionFunc + } + + head := &Bundle{ + Name: "anakin.v0.0.3", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + } + + specs := []spec{ + { + name: "Success/Valid", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1"}, + "anakin.v0.0.2": {Name: "anakin.v0.0.2"}, + "anakin.v0.0.3": head, + }}, + head: head, + assertion: require.NoError, + }, + { + name: "Error/NoChannelHead", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1", Replaces: "anakin.v0.0.3"}, + "anakin.v0.0.3": head, + }}, + assertion: hasError(`no channel head found in graph`), + }, + { + name: "Error/MultipleChannelHeads", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1"}, + "anakin.v0.0.3": head, + "anakin.v0.0.4": {Name: "anakin.v0.0.4", Replaces: "anakin.v0.0.1"}, + }}, + assertion: hasError(`multiple channel heads found in graph: anakin.v0.0.3, anakin.v0.0.4`), + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + h, err := s.ch.Head() + assert.Equal(t, s.head, h) + s.assertion(t, err) + }) + } +} + +func TestValidReplacesChain(t *testing.T) { + type spec struct { + name string + ch Channel + assertion require.ErrorAssertionFunc + } + specs := []spec{ + { + name: "Success/Valid", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1"}, + "anakin.v0.0.2": {Name: "anakin.v0.0.2", Skips: []string{"anakin.v0.0.1"}}, + "anakin.v0.0.3": {Name: "anakin.v0.0.3", Skips: []string{"anakin.v0.0.2"}}, + "anakin.v0.0.4": {Name: "anakin.v0.0.4", Replaces: "anakin.v0.0.3"}, + }}, + assertion: require.NoError, + }, + { + name: "Error/CycleNoHops", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.4": {Name: "anakin.v0.0.4", Replaces: "anakin.v0.0.4"}, + "anakin.v0.0.5": {Name: "anakin.v0.0.5", Replaces: "anakin.v0.0.4"}, + }}, + assertion: hasError(`detected cycle in replaces chain of upgrade graph: anakin.v0.0.4 -> anakin.v0.0.4`), + }, + { + name: "Error/CycleMultipleHops", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1", Replaces: "anakin.v0.0.3"}, + "anakin.v0.0.2": {Name: "anakin.v0.0.2", Replaces: "anakin.v0.0.1"}, + "anakin.v0.0.3": {Name: "anakin.v0.0.3", Replaces: "anakin.v0.0.2"}, + "anakin.v0.0.4": {Name: "anakin.v0.0.4", Replaces: "anakin.v0.0.3"}, + }}, + assertion: hasError(`detected cycle in replaces chain of upgrade graph: anakin.v0.0.3 -> anakin.v0.0.2 -> anakin.v0.0.1 -> anakin.v0.0.3`), + }, + { + name: "Error/Stranded", + ch: Channel{Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1"}, + "anakin.v0.0.2": {Name: "anakin.v0.0.2", Replaces: "anakin.v0.0.1"}, + "anakin.v0.0.3": {Name: "anakin.v0.0.3", Skips: []string{"anakin.v0.0.2"}}, + }}, + assertion: hasError(`channel contains one or more stranded bundles: anakin.v0.0.1`), + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + err := s.ch.validateReplacesChain() + s.assertion(t, err) + }) + } +} + +func hasError(expectedError string) require.ErrorAssertionFunc { + return func(t require.TestingT, actualError error, args ...interface{}) { + if stdt, ok := t.(*testing.T); ok { + stdt.Helper() + } + errsToCheck := []error{actualError} + for len(errsToCheck) > 0 { + var err error + err, errsToCheck = errsToCheck[0], errsToCheck[1:] + if err == nil { + continue + } + var verr *validationError + if errors.As(err, &verr) { + if verr.message == expectedError { + return + } + errsToCheck = append(errsToCheck, verr.subErrors...) + } else if expectedError == err.Error() { + return + } + } + t.Errorf("expected error to be or contain suberror `%s`, got `%s`", expectedError, actualError) + t.FailNow() + } +} + +func TestValidators(t *testing.T) { + type spec struct { + name string + v validator + assertion require.ErrorAssertionFunc + } + + pkg, ch := makePackageChannelBundle() + pkgIncorrectDefaultChannel, _ := makePackageChannelBundle() + pkgIncorrectDefaultChannel.DefaultChannel = &Channel{Name: "not-found"} + + var nilIcon *Icon = nil + + specs := []spec{ + { + name: "Model/Success/Valid", + v: Model{ + pkg.Name: pkg, + }, + assertion: require.NoError, + }, + { + name: "Model/Error/PackageKeyNameMismatch", + v: Model{ + "foo": pkg, + }, + assertion: hasError(`package key "foo" does not match package name "anakin"`), + }, + { + name: "Model/Error/InvalidPackage", + v: Model{ + pkgIncorrectDefaultChannel.Name: pkgIncorrectDefaultChannel, + }, + assertion: hasError(`invalid package "anakin"`), + }, + { + name: "Package/Success/Valid", + v: pkg, + assertion: require.NoError, + }, + { + name: "Package/Error/NoName", + v: &Package{}, + assertion: hasError("package name must not be empty"), + }, + //{ + // name: "Package/Error/InvalidIcon", + // v: &Package{ + // Name: "anakin", + // Icon: &Icon{Data: mustBase64Decode(svgData)}, + // }, + // assertion: hasError("icon mediatype must be set if icon is defined"), + //}, + { + name: "Package/Error/NoChannels", + v: &Package{ + Name: "anakin", + Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, + }, + assertion: hasError("package must contain at least one channel"), + }, + { + name: "Package/Error/DuplicateBundleVersions", + v: &Package{ + Name: "anakin", + Channels: map[string]*Channel{ + "light": { + Package: pkg, + Name: "light", + Bundles: map[string]*Bundle{ + "anakin.v0.0.1": {Name: "anakin.v0.0.1", Version: semver.MustParse("0.0.1")}, + "anakin.v0.0.2": {Name: "anakin.v0.0.2", Version: semver.MustParse("0.0.1")}, + "anakin.v1.0.1": {Name: "anakin.v1.0.1", Version: semver.MustParse("1.0.1")}, + "anakin.v1.0.2": {Name: "anakin.v1.0.2", Version: semver.MustParse("1.0.1")}, + }, + }, + }, + }, + assertion: hasError(`duplicate versions found in bundles: [{0.0.1: [anakin.v0.0.1, anakin.v0.0.2]} {1.0.1: [anakin.v1.0.1, anakin.v1.0.2]}]`), + }, + { + name: "Package/Error/NoDefaultChannel", + v: &Package{ + Name: "anakin", + Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, + Channels: map[string]*Channel{"light": ch}, + }, + assertion: hasError("default channel must be set"), + }, + { + name: "Package/Error/ChannelKeyNameMismatch", + v: &Package{ + Name: "anakin", + Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, + DefaultChannel: ch, + Channels: map[string]*Channel{"dark": ch}, + }, + assertion: hasError(`channel key "dark" does not match channel name "light"`), + }, + { + name: "Package/Error/InvalidChannel", + v: &Package{ + Name: "anakin", + Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, + DefaultChannel: ch, + Channels: map[string]*Channel{"light": {Name: "light"}}, + }, + assertion: hasError(`invalid channel "light"`), + }, + { + name: "Package/Error/InvalidChannelPackageLink", + v: &Package{ + Name: "anakin", + Icon: &Icon{Data: mustBase64Decode(svgData), MediaType: "image/svg+xml"}, + DefaultChannel: ch, + Channels: map[string]*Channel{"light": ch}, + }, + assertion: hasError(`channel "light" not correctly linked to parent package`), + }, + { + name: "Package/Error/DefaultChannelNotInChannelMap", + v: pkgIncorrectDefaultChannel, + assertion: hasError(`default channel "not-found" not found in channels list`), + }, + { + name: "Icon/Success/ValidSVG", + v: &Icon{ + Data: mustBase64Decode(svgData), + MediaType: "image/svg+xml", + }, + assertion: require.NoError, + }, + { + name: "Icon/Success/ValidPNG", + v: &Icon{ + Data: mustBase64Decode(pngData), + MediaType: "image/png", + }, + assertion: require.NoError, + }, + { + name: "Icon/Success/ValidJPEG", + v: &Icon{ + Data: mustBase64Decode(jpegData), + MediaType: "image/jpeg", + }, + assertion: require.NoError, + }, + { + name: "Icon/Success/Nil", + v: nilIcon, + assertion: require.NoError, + }, + //{ + // name: "Icon/Error/NoData", + // v: &Icon{ + // Data: nil, + // MediaType: "image/svg+xml", + // }, + // assertion: hasError(`icon data must be set if icon is defined`), + //}, + //{ + // name: "Icon/Error/NoMediaType", + // v: &Icon{ + // Data: mustBase64Decode(svgData), + // MediaType: "", + // }, + // assertion: hasError(`icon mediatype must be set if icon is defined`), + //}, + //{ + // name: "Icon/Error/DataIsNotImage", + // v: &Icon{ + // Data: []byte("{}"), + // MediaType: "application/json", + // }, + // assertion: hasError(`icon data is not an image`), + //}, + //{ + // name: "Icon/Error/DataDoesNotMatchMediaType", + // v: &Icon{ + // Data: mustBase64Decode(svgData), + // MediaType: "image/jpeg", + // }, + // assertion: hasError(`icon media type "image/jpeg" does not match detected media type "image/svg+xml"`), + //}, + { + name: "Channel/Success/Valid", + v: ch, + assertion: require.NoError, + }, + { + name: "Channel/Error/NoName", + v: &Channel{}, + assertion: hasError(`channel name must not be empty`), + }, + { + name: "Channel/Error/NoPackage", + v: &Channel{ + Name: "light", + }, + assertion: hasError(`package must be set`), + }, + { + name: "Channel/Error/NoBundles", + v: &Channel{ + Package: pkg, + Name: "light", + }, + assertion: hasError(`channel must contain at least one bundle`), + }, + { + name: "Channel/Error/InvalidHead", + v: &Channel{ + Package: pkg, + Name: "light", + Bundles: map[string]*Bundle{ + "anakin.v0.0.0": {Name: "anakin.v0.0.0"}, + "anakin.v0.0.1": {Name: "anakin.v0.0.1"}, + }, + }, + assertion: hasError(`multiple channel heads found in graph: anakin.v0.0.0, anakin.v0.0.1`), + }, + { + name: "Channel/Error/BundleKeyNameMismatch", + v: &Channel{ + Package: pkg, + Name: "light", + Bundles: map[string]*Bundle{ + "foo": {Name: "bar"}, + }, + }, + assertion: hasError(`bundle key "foo" does not match bundle name "bar"`), + }, + { + name: "Channel/Error/InvalidBundle", + v: &Channel{ + Package: pkg, + Name: "light", + Bundles: map[string]*Bundle{ + "anakin.v0.0.0": {Name: "anakin.v0.0.0"}, + }, + }, + assertion: hasError(`invalid bundle "anakin.v0.0.0"`), + }, + { + name: "Channel/Error/InvalidBundleChannelLink", + v: &Channel{ + Package: pkg, + Name: "light", + Bundles: map[string]*Bundle{ + "anakin.v0.0.0": { + Package: pkg, + Channel: ch, + Name: "anakin.v0.0.0", + Image: "anakin-operator:v0.0.0", + }, + }, + }, + assertion: hasError(`bundle "anakin.v0.0.0" not correctly linked to parent channel`), + }, + { + name: "Bundle/Success/Valid", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "registry.io/image", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.1.0"), + property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"), + }, + }, + assertion: require.NoError, + }, + { + name: "Bundle/Success/ReplacesNotInChannel", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "registry.io/image", + Replaces: "anakin.v0.0.0", + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.1.0"), + }, + }, + assertion: require.NoError, + }, + { + name: "Bundle/Success/NoBundleImage/HaveBundleData", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "", + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.1.0"), + property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"), + property.MustBuildBundleObject([]byte("testdata")), + }, + Objects: []string{"testdata"}, + CsvJSON: "CSVjson", + }, + assertion: require.NoError, + }, + { + name: "Bundle/Error/NoBundleImage", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "", + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.1.0"), + property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"), + }, + }, + assertion: hasError(`bundle image must be set`), + }, + { + name: "Bundle/Error/NoName", + v: &Bundle{}, + assertion: hasError(`name must be set`), + }, + { + name: "Bundle/Error/NoChannel", + v: &Bundle{ + Name: "anakin.v0.1.0", + }, + assertion: hasError(`channel must be set`), + }, + { + name: "Bundle/Error/NoPackage", + v: &Bundle{ + Channel: ch, + Name: "anakin.v0.1.0", + }, + assertion: hasError(`package must be set`), + }, + { + name: "Bundle/Error/WrongPackage", + v: &Bundle{ + Package: &Package{}, + Channel: ch, + Name: "anakin.v0.1.0", + }, + assertion: hasError(`package does not match channel's package`), + }, + { + name: "Bundle/Error/InvalidProperty", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Replaces: "anakin.v0.0.1", + Properties: []property.Property{{Type: "broken", Value: json.RawMessage("")}}, + }, + assertion: hasError(`parse property[0] of type "broken": unexpected end of JSON input`), + }, + { + name: "Bundle/Error/EmptySkipsValue", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Replaces: "anakin.v0.0.1", + Properties: []property.Property{{Type: "custom", Value: json.RawMessage("{}")}}, + Skips: []string{""}, + }, + assertion: hasError(`skip[0] is empty`), + }, + { + name: "Bundle/Error/MissingPackage", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Properties: []property.Property{}, + }, + assertion: hasError(`must be exactly one property with type "olm.package"`), + }, + { + name: "Bundle/Error/MultiplePackages", + v: &Bundle{ + Package: pkg, + Channel: ch, + Name: "anakin.v0.1.0", + Image: "", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.1.0"), + property.MustBuildPackage("anakin", "0.2.0"), + }, + }, + assertion: hasError(`must be exactly one property with type "olm.package"`), + }, + { + name: "RelatedImage/Success/Valid", + v: RelatedImage{ + Name: "foo", + Image: "bar", + }, + assertion: require.NoError, + }, + { + name: "RelatedImage/Error/NoImage", + v: RelatedImage{ + Name: "foo", + Image: "", + }, + assertion: hasError(`image must be set`), + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + s.assertion(t, s.v.Validate()) + }) + } +} + +func makePackageChannelBundle() (*Package, *Channel) { + bundle1 := &Bundle{ + Name: "anakin.v0.0.1", + Image: "anakin-operator:v0.0.1", + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.0.1"), + property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"), + }, + Version: semver.MustParse("0.0.1"), + } + bundle2 := &Bundle{ + Name: "anakin.v0.0.2", + Image: "anakin-operator:v0.0.2", + Replaces: "anakin.v0.0.1", + Properties: []property.Property{ + property.MustBuildPackage("anakin", "0.0.2"), + property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"), + }, + Version: semver.MustParse("0.0.2"), + } + ch := &Channel{ + Name: "light", + Bundles: map[string]*Bundle{ + "anakin.v0.0.1": bundle1, + "anakin.v0.0.2": bundle2, + }, + } + pkg := &Package{ + Name: "anakin", + DefaultChannel: ch, + Channels: map[string]*Channel{ + ch.Name: ch, + }, + } + + bundle1.Channel, bundle2.Channel = ch, ch + bundle1.Package, bundle2.Package, ch.Package = pkg, pkg, pkg + + return pkg, ch +} + +func TestAddBundle(t *testing.T) { + type spec struct { + name string + model Model + bundle Bundle + numPkgIncrease bool + numBundlesIncrease bool + pkgBundleAddedTo string + } + pkg, _ := makePackageChannelBundle() + m := Model{} + m[pkg.Name] = pkg + + bundle1 := Bundle{ + Name: "darth.vader.v0.0.1", + Replaces: "anakin.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Package: &Package{Name: pkg.Name}, + } + ch1 := &Channel{ + Name: "darkness", + Bundles: map[string]*Bundle{ + "vader.v0.0.1": &bundle1, + }, + } + bundle1.Channel = ch1 + + bundle2 := Bundle{ + Name: "kylo.ren.v0.0.1", + Replaces: "darth.vader.v0.0.1", + Skips: []string{"anakin.v0.0.2"}, + Package: &Package{ + Name: "Empire", + Description: "The Empire Will Rise Again", + Icon: &Icon{ + MediaType: "gif", + Data: []byte("palpatineLaughing"), + }, + Channels: make(map[string]*Channel), + }, + } + ch2 := &Channel{ + Name: "darkeness", + Bundles: map[string]*Bundle{ + "kylo.ren.v0.0.1": &bundle2, + }, + } + bundle2.Channel = ch2 + bundle2.Package.Channels[ch2.Name] = ch2 + + specs := []spec{ + { + name: "AddingToExistingPackage", + bundle: bundle1, + model: m, + numPkgIncrease: false, + numBundlesIncrease: true, + pkgBundleAddedTo: bundle1.Package.Name, + }, + { + name: "AddingNewPackage", + bundle: bundle2, + model: m, + numPkgIncrease: true, + numBundlesIncrease: false, + pkgBundleAddedTo: "", + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + existingPkgCount := len(s.model) + existingBundleCount := 0 + if s.pkgBundleAddedTo != "" { + existingBundleCount = countBundles(m, s.pkgBundleAddedTo) + } + s.model.AddBundle(s.bundle) + if s.numPkgIncrease { + assert.Equal(t, len(s.model), existingPkgCount+1) + } + if s.numBundlesIncrease { + assert.Equal(t, countBundles(m, s.pkgBundleAddedTo), existingBundleCount+1) + } + }) + } +} + +func countBundles(m Model, pkg string) int { + count := 0 + mpkg := m[pkg] + for _, ch := range mpkg.Channels { + count += len(ch.Bundles) + } + return count +} diff --git a/alpha/property/errors.go b/alpha/property/errors.go new file mode 100644 index 000000000..6c3689c5b --- /dev/null +++ b/alpha/property/errors.go @@ -0,0 +1,25 @@ +package property + +import ( + "fmt" +) + +type ParseError struct { + Idx int + Typ string + Err error +} + +func (e ParseError) Error() string { + return fmt.Sprintf("parse property[%d] of type %q: %v", e.Idx, e.Typ, e.Err) +} + +type MatchMissingError struct { + foundType string + foundValue interface{} + expectedType string +} + +func (e MatchMissingError) Error() string { + return fmt.Sprintf("property %q for %+v requires matching %q property", e.foundType, e.foundValue, e.expectedType) +} diff --git a/alpha/property/property.go b/alpha/property/property.go new file mode 100644 index 000000000..6fb792dda --- /dev/null +++ b/alpha/property/property.go @@ -0,0 +1,288 @@ +package property + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "reflect" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/operator-framework/api/pkg/operators/v1alpha1" +) + +type Property struct { + Type string `json:"type"` + Value json.RawMessage `json:"value"` +} + +func (p Property) Validate() error { + if len(p.Type) == 0 { + return errors.New("type must be set") + } + if len(p.Value) == 0 { + return errors.New("value must be set") + } + var raw json.RawMessage + if err := json.Unmarshal(p.Value, &raw); err != nil { + return fmt.Errorf("value is not valid json: %v", err) + } + return nil +} + +func (p Property) String() string { + return fmt.Sprintf("type: %q, value: %q", p.Type, p.Value) +} + +type Package struct { + PackageName string `json:"packageName"` + Version string `json:"version"` +} + +// NOTICE: The Channel properties are for internal use only. +// +// DO NOT use it for any public-facing functionalities. +// This API is in alpha stage and it is subject to change. +type Channel struct { + ChannelName string `json:"channelName"` + //Priority string `json:"priority"` + Priority int `json:"priority"` +} + +type PackageRequired struct { + PackageName string `json:"packageName"` + VersionRange string `json:"versionRange"` +} + +type GVK struct { + Group string `json:"group"` + Kind string `json:"kind"` + Version string `json:"version"` +} + +type GVKRequired struct { + Group string `json:"group"` + Kind string `json:"kind"` + Version string `json:"version"` +} + +type BundleObject struct { + Data []byte `json:"data"` +} + +type CSVMetadata struct { + Annotations map[string]string `json:"annotations,omitempty"` + APIServiceDefinitions v1alpha1.APIServiceDefinitions `json:"apiServiceDefinitions,omitempty"` + CustomResourceDefinitions v1alpha1.CustomResourceDefinitions `json:"crdDescriptions,omitempty"` + Description string `json:"description,omitempty"` + DisplayName string `json:"displayName,omitempty"` + InstallModes []v1alpha1.InstallMode `json:"installModes,omitempty"` + Keywords []string `json:"keywords,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Links []v1alpha1.AppLink `json:"links,omitempty"` + Maintainers []v1alpha1.Maintainer `json:"maintainers,omitempty"` + Maturity string `json:"maturity,omitempty"` + MinKubeVersion string `json:"minKubeVersion,omitempty"` + NativeAPIs []metav1.GroupVersionKind `json:"nativeAPIs,omitempty"` + Provider v1alpha1.AppLink `json:"provider,omitempty"` +} + +type Properties struct { + Packages []Package `hash:"set"` + PackagesRequired []PackageRequired `hash:"set"` + GVKs []GVK `hash:"set"` + GVKsRequired []GVKRequired `hash:"set"` + BundleObjects []BundleObject `hash:"set"` + Channels []Channel `hash:"set"` + CSVMetadatas []CSVMetadata `hash:"set"` + + Others []Property `hash:"set"` +} + +const ( + TypePackage = "olm.package" + TypePackageRequired = "olm.package.required" + TypeGVK = "olm.gvk" + TypeGVKRequired = "olm.gvk.required" + TypeBundleObject = "olm.bundle.object" + TypeCSVMetadata = "olm.csv.metadata" + TypeConstraint = "olm.constraint" + TypeChannel = "olm.channel" +) + +func Parse(in []Property) (*Properties, error) { + var out Properties + for i, prop := range in { + switch prop.Type { + case TypePackage: + var p Package + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.Packages = append(out.Packages, p) + case TypePackageRequired: + var p PackageRequired + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.PackagesRequired = append(out.PackagesRequired, p) + case TypeGVK: + var p GVK + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.GVKs = append(out.GVKs, p) + case TypeGVKRequired: + var p GVKRequired + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.GVKsRequired = append(out.GVKsRequired, p) + case TypeBundleObject: + var p BundleObject + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.BundleObjects = append(out.BundleObjects, p) + case TypeCSVMetadata: + var p CSVMetadata + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.CSVMetadatas = append(out.CSVMetadatas, p) + // NOTICE: The Channel properties are for internal use only. + // DO NOT use it for any public-facing functionalities. + // This API is in alpha stage and it is subject to change. + case TypeChannel: + var p Channel + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.Channels = append(out.Channels, p) + default: + var p json.RawMessage + if err := json.Unmarshal(prop.Value, &p); err != nil { + return nil, ParseError{Idx: i, Typ: prop.Type, Err: err} + } + out.Others = append(out.Others, prop) + } + } + return &out, nil +} + +func Deduplicate(in []Property) []Property { + type key struct { + typ string + value string + } + + props := map[key]Property{} + // nolint:prealloc + var out []Property + for _, p := range in { + k := key{p.Type, string(p.Value)} + if _, ok := props[k]; ok { + continue + } + props[k] = p + out = append(out, p) + } + return out +} + +func Build(p interface{}) (*Property, error) { + var ( + typ string + val interface{} + ) + if prop, ok := p.(*Property); ok { + typ = prop.Type + val = prop.Value + } else { + t := reflect.TypeOf(p) + if t.Kind() != reflect.Ptr { + return nil, errors.New("input must be a pointer to a type") + } + typ, ok = scheme[t] + if !ok { + return nil, fmt.Errorf("%s not a known property type registered with the scheme", t) + } + val = p + } + d, err := jsonMarshal(val) + if err != nil { + return nil, err + } + + return &Property{ + Type: typ, + Value: d, + }, nil +} + +func MustBuild(p interface{}) Property { + prop, err := Build(p) + if err != nil { + panic(err) + } + return *prop +} + +func jsonMarshal(p interface{}) ([]byte, error) { + buf := &bytes.Buffer{} + dec := json.NewEncoder(buf) + dec.SetEscapeHTML(false) + err := dec.Encode(p) + if err != nil { + return nil, err + } + out := &bytes.Buffer{} + if err := json.Compact(out, buf.Bytes()); err != nil { + return nil, err + } + return out.Bytes(), nil +} + +func MustBuildPackage(name, version string) Property { + return MustBuild(&Package{PackageName: name, Version: version}) +} +func MustBuildPackageRequired(name, versionRange string) Property { + return MustBuild(&PackageRequired{name, versionRange}) +} +func MustBuildGVK(group, version, kind string) Property { + return MustBuild(&GVK{group, kind, version}) +} +func MustBuildGVKRequired(group, version, kind string) Property { + return MustBuild(&GVKRequired{group, kind, version}) +} +func MustBuildBundleObject(data []byte) Property { + return MustBuild(&BundleObject{Data: data}) +} + +func MustBuildCSVMetadata(csv v1alpha1.ClusterServiceVersion) Property { + return MustBuild(&CSVMetadata{ + Annotations: csv.GetAnnotations(), + APIServiceDefinitions: csv.Spec.APIServiceDefinitions, + CustomResourceDefinitions: csv.Spec.CustomResourceDefinitions, + Description: csv.Spec.Description, + DisplayName: csv.Spec.DisplayName, + InstallModes: csv.Spec.InstallModes, + Keywords: csv.Spec.Keywords, + Labels: csv.GetLabels(), + Links: csv.Spec.Links, + Maintainers: csv.Spec.Maintainers, + Maturity: csv.Spec.Maturity, + MinKubeVersion: csv.Spec.MinKubeVersion, + NativeAPIs: csv.Spec.NativeAPIs, + Provider: csv.Spec.Provider, + }) +} + +// NOTICE: The Channel properties are for internal use only. +// +// DO NOT use it for any public-facing functionalities. +// This API is in alpha stage and it is subject to change. +func MustBuildChannelPriority(name string, priority int) Property { + return MustBuild(&Channel{ChannelName: name, Priority: priority}) +} diff --git a/alpha/property/property_test.go b/alpha/property/property_test.go new file mode 100644 index 000000000..171cec7a0 --- /dev/null +++ b/alpha/property/property_test.go @@ -0,0 +1,275 @@ +package property + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidate(t *testing.T) { + type spec struct { + name string + v Property + assertion require.ErrorAssertionFunc + } + + specs := []spec{ + { + name: "Success/Valid", + v: Property{ + Type: "custom.type", + Value: json.RawMessage("{}"), + }, + assertion: require.NoError, + }, + { + name: "Error/NoType", + v: Property{ + Value: json.RawMessage(""), + }, + assertion: require.Error, + }, + { + name: "Error/NoValue", + v: Property{ + Type: "custom.type", + Value: nil, + }, + assertion: require.Error, + }, + { + name: "Error/EmptyValue", + v: Property{ + Type: "custom.type", + Value: json.RawMessage{}, + }, + assertion: require.Error, + }, + { + name: "Error/ValueNotJSON", + v: Property{ + Type: "custom.type", + Value: json.RawMessage("{"), + }, + assertion: require.Error, + }, + } + + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + err := s.v.Validate() + s.assertion(t, err) + }) + } +} + +func TestParse(t *testing.T) { + type spec struct { + name string + input []Property + expectProps *Properties + assertion assert.ErrorAssertionFunc + } + specs := []spec{ + { + name: "Error/InvalidPackage", + input: []Property{ + {Type: TypePackage, Value: json.RawMessage(`{`)}, + }, + assertion: assert.Error, + }, + { + name: "Error/InvalidPackageRequired", + input: []Property{ + {Type: TypePackageRequired, Value: json.RawMessage(`{`)}, + }, + assertion: assert.Error, + }, + { + name: "Error/InvalidGVK", + input: []Property{ + {Type: TypeGVK, Value: json.RawMessage(`{`)}, + }, + assertion: assert.Error, + }, + { + name: "Error/InvalidGVKRequired", + input: []Property{ + {Type: TypeGVKRequired, Value: json.RawMessage(`{`)}, + }, + assertion: assert.Error, + }, + { + name: "Error/InvalidBundleObject", + input: []Property{ + {Type: TypeBundleObject, Value: json.RawMessage(`{`)}, + }, + assertion: assert.Error, + }, + { + name: "Error/InvalidOther", + input: []Property{ + {Type: "otherType1", Value: json.RawMessage(`{`)}, + }, + assertion: assert.Error, + }, + { + name: "Success/Valid", + input: []Property{ + MustBuildPackage("package1", "0.1.0"), + MustBuildPackage("package2", "0.2.0"), + MustBuildPackageRequired("package3", ">=1.0.0 <2.0.0-0"), + MustBuildPackageRequired("package4", ">=2.0.0 <3.0.0-0"), + MustBuildGVK("group", "v1", "Kind1"), + MustBuildGVK("group", "v1", "Kind2"), + MustBuildGVKRequired("other", "v2", "Kind3"), + MustBuildGVKRequired("other", "v2", "Kind4"), + MustBuildBundleObject([]byte("testdata2")), + {Type: "otherType1", Value: json.RawMessage(`{"v":"otherValue1"}`)}, + {Type: "otherType2", Value: json.RawMessage(`["otherValue2"]`)}, + }, + expectProps: &Properties{ + Packages: []Package{ + {"package1", "0.1.0"}, + {"package2", "0.2.0"}, + }, + PackagesRequired: []PackageRequired{ + {"package3", ">=1.0.0 <2.0.0-0"}, + {"package4", ">=2.0.0 <3.0.0-0"}, + }, + GVKs: []GVK{ + {"group", "Kind1", "v1"}, + {"group", "Kind2", "v1"}, + }, + GVKsRequired: []GVKRequired{ + {"other", "Kind3", "v2"}, + {"other", "Kind4", "v2"}, + }, + BundleObjects: []BundleObject{ + {Data: []byte("testdata2")}, + }, + Others: []Property{ + {Type: "otherType1", Value: json.RawMessage(`{"v":"otherValue1"}`)}, + {Type: "otherType2", Value: json.RawMessage(`["otherValue2"]`)}, + }, + }, + assertion: assert.NoError, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + actual, err := Parse(s.input) + s.assertion(t, err) + assert.Equal(t, s.expectProps, actual) + }) + } +} + +func TestDeduplicate(t *testing.T) { + type spec struct { + name string + input []Property + expectProps []Property + } + specs := []spec{ + { + name: "Identical", + input: []Property{ + MustBuildPackage("package1", "0.1.0"), + MustBuildGVK("group", "v1", "Kind"), + MustBuildGVK("group", "v1", "Kind"), + MustBuildGVK("group", "v1", "Kind"), + }, + expectProps: []Property{ + MustBuildPackage("package1", "0.1.0"), + MustBuildGVK("group", "v1", "Kind"), + }, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + actual := Deduplicate(s.input) + assert.Equal(t, s.expectProps, actual) + }) + } +} + +func TestBuild(t *testing.T) { + type spec struct { + name string + input interface{} + assertion require.ErrorAssertionFunc + expectedProperty *Property + } + specs := []spec{ + { + name: "Success/Package", + input: &Package{"name", "0.1.0"}, + assertion: require.NoError, + expectedProperty: propPtr(MustBuildPackage("name", "0.1.0")), + }, + { + name: "Success/PackageRequired", + input: &PackageRequired{"name", ">=0.1.0"}, + assertion: require.NoError, + expectedProperty: propPtr(MustBuildPackageRequired("name", ">=0.1.0")), + }, + { + name: "Success/GVK", + input: &GVK{"group", "Kind", "v1"}, + assertion: require.NoError, + expectedProperty: propPtr(MustBuildGVK("group", "v1", "Kind")), + }, + { + name: "Success/GVKRequired", + input: &GVKRequired{"group", "Kind", "v1"}, + assertion: require.NoError, + expectedProperty: propPtr(MustBuildGVKRequired("group", "v1", "Kind")), + }, + { + name: "Success/BundleObject", + input: &BundleObject{Data: []byte("test")}, + assertion: require.NoError, + expectedProperty: propPtr(MustBuildBundleObject([]byte("test"))), + }, + { + name: "Success/Property", + input: &Property{Type: "foo", Value: json.RawMessage(`"bar"`)}, + assertion: require.NoError, + expectedProperty: &Property{Type: "foo", Value: json.RawMessage(`"bar"`)}, + }, + { + name: "Error/InvalidProperty", + input: &Property{Type: "foo", Value: json.RawMessage(`{`)}, + assertion: require.Error, + }, + { + name: "Error/NotAPointer", + input: Package{}, + assertion: require.Error, + }, + { + name: "Error/NotRegisteredInScheme", + input: &struct{}{}, + assertion: require.Error, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + actual, err := Build(s.input) + s.assertion(t, err) + assert.Equal(t, s.expectedProperty, actual) + }) + } +} + +func TestMustBuild(t *testing.T) { + assert.NotPanics(t, func() { MustBuild(&Package{}) }) + assert.Panics(t, func() { MustBuild(Package{}) }) +} + +func propPtr(in Property) *Property { + return &in +} diff --git a/alpha/property/scheme.go b/alpha/property/scheme.go new file mode 100644 index 000000000..ab176856f --- /dev/null +++ b/alpha/property/scheme.go @@ -0,0 +1,34 @@ +package property + +import ( + "fmt" + "reflect" +) + +func init() { + scheme = map[reflect.Type]string{ + reflect.TypeOf(&Package{}): TypePackage, + reflect.TypeOf(&PackageRequired{}): TypePackageRequired, + reflect.TypeOf(&GVK{}): TypeGVK, + reflect.TypeOf(&GVKRequired{}): TypeGVKRequired, + reflect.TypeOf(&BundleObject{}): TypeBundleObject, + reflect.TypeOf(&CSVMetadata{}): TypeCSVMetadata, + // NOTICE: The Channel properties are for internal use only. + // DO NOT use it for any public-facing functionalities. + // This API is in alpha stage and it is subject to change. + reflect.TypeOf(&Channel{}): TypeChannel, + } +} + +var scheme map[reflect.Type]string + +func AddToScheme(typ string, p interface{}) { + t := reflect.TypeOf(p) + if t.Kind() != reflect.Ptr { + panic("input must be a pointer to a type") + } + if _, ok := scheme[t]; ok { + panic(fmt.Sprintf("scheme already contains registration for type %q", t)) + } + scheme[t] = typ +} diff --git a/alpha/property/scheme_test.go b/alpha/property/scheme_test.go new file mode 100644 index 000000000..81810c3d9 --- /dev/null +++ b/alpha/property/scheme_test.go @@ -0,0 +1,46 @@ +package property + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddToScheme(t *testing.T) { + type custom struct { + Name string `json:"name"` + } + + type spec struct { + name string + typ string + val interface{} + assertion func(assert.TestingT, assert.PanicTestFunc, ...interface{}) bool + } + specs := []spec{ + { + name: "Success/CustomTypeValue", + typ: "custom1", + val: &custom{}, + assertion: assert.NotPanics, + }, + { + name: "Panic/MustBeAPointer", + typ: TypePackage, + val: custom{}, + assertion: assert.Panics, + }, + { + name: "Panic/AlreadyRegistered", + typ: TypePackage, + val: &custom{}, + assertion: assert.Panics, + }, + } + for _, s := range specs { + t.Run(s.name, func(t *testing.T) { + f := func() { AddToScheme(s.typ, s.val) } + s.assertion(t, f) + }) + } +} diff --git a/alpha/template/basic/basic.go b/alpha/template/basic/basic.go new file mode 100644 index 000000000..a34d7541d --- /dev/null +++ b/alpha/template/basic/basic.go @@ -0,0 +1,110 @@ +package basic + +import ( + "context" + "encoding/json" + "fmt" + "io" + + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/operator-framework/operator-registry/alpha/declcfg" +) + +const schema string = "olm.template.basic" + +type Template struct { + RenderBundle func(context.Context, string) (*declcfg.DeclarativeConfig, error) +} + +type BasicTemplate struct { + Schema string `json:"schema"` + Entries []*declcfg.Meta `json:"entries"` +} + +func parseSpec(reader io.Reader) (*BasicTemplate, error) { + bt := &BasicTemplate{} + btDoc := json.RawMessage{} + btDecoder := yaml.NewYAMLOrJSONDecoder(reader, 4096) + err := btDecoder.Decode(&btDoc) + if err != nil { + return nil, fmt.Errorf("decoding template schema: %v", err) + } + err = json.Unmarshal(btDoc, bt) + if err != nil { + return nil, fmt.Errorf("unmarshalling template: %v", err) + } + + if bt.Schema != schema { + return nil, fmt.Errorf("template has unknown schema (%q), should be %q", bt.Schema, schema) + } + + return bt, nil +} + +func (t Template) Render(ctx context.Context, reader io.Reader) (*declcfg.DeclarativeConfig, error) { + bt, err := parseSpec(reader) + if err != nil { + return nil, err + } + cfg, err := declcfg.LoadSlice(bt.Entries) + if err != nil { + return cfg, err + } + + outb := cfg.Bundles[:0] + for _, b := range cfg.Bundles { + if !isBundleTemplate(&b) { + return nil, fmt.Errorf("unexpected fields present in basic template bundle") + } + contributor, err := t.RenderBundle(ctx, b.Image) + if err != nil { + return nil, err + } + outb = append(outb, contributor.Bundles...) + } + + cfg.Bundles = outb + return cfg, nil +} + +// isBundleTemplate identifies a Bundle template source as having a Schema and Image defined +// but no Properties, RelatedImages or Package defined +func isBundleTemplate(b *declcfg.Bundle) bool { + return b.Schema != "" && b.Image != "" && b.Package == "" && len(b.Properties) == 0 && len(b.RelatedImages) == 0 +} + +// FromReader reads FBC from a reader and generates a BasicTemplate from it +func FromReader(r io.Reader) (*BasicTemplate, error) { + var entries []*declcfg.Meta + if err := declcfg.WalkMetasReader(r, func(meta *declcfg.Meta, err error) error { + if err != nil { + return err + } + if meta.Schema == declcfg.SchemaBundle { + var b declcfg.Bundle + if err := json.Unmarshal(meta.Blob, &b); err != nil { + return fmt.Errorf("parse bundle: %v", err) + } + b2 := declcfg.Bundle{ + Schema: b.Schema, + Image: b.Image, + } + meta.Blob, err = json.Marshal(b2) + if err != nil { + return fmt.Errorf("re-serialize bundle: %v", err) + } + } + entries = append(entries, meta) + return nil + }); err != nil { + return nil, err + } + + bt := &BasicTemplate{ + Schema: schema, + Entries: entries, + } + + return bt, nil +} diff --git a/alpha/template/converter/converter.go b/alpha/template/converter/converter.go new file mode 100644 index 000000000..03e3e0a97 --- /dev/null +++ b/alpha/template/converter/converter.go @@ -0,0 +1,40 @@ +package converter + +import ( + "encoding/json" + "fmt" + "io" + "os" + + "sigs.k8s.io/yaml" + + "github.com/operator-framework/operator-registry/alpha/template/basic" + "github.com/operator-framework/operator-registry/pkg/image" +) + +type Converter struct { + FbcReader io.Reader + OutputFormat string + Registry image.Registry +} + +func (c *Converter) Convert() error { + bt, err := basic.FromReader(c.FbcReader) + if err != nil { + return err + } + + b, _ := json.MarshalIndent(bt, "", " ") + if c.OutputFormat == "json" { + fmt.Fprintln(os.Stdout, string(b)) + } else { + y, err := yaml.JSONToYAML(b) + if err != nil { + return err + } + y = append([]byte("---\n"), y...) + fmt.Fprintln(os.Stdout, string(y)) + } + + return nil +} diff --git a/alpha/template/semver/README.md b/alpha/template/semver/README.md new file mode 100644 index 000000000..ace33746a --- /dev/null +++ b/alpha/template/semver/README.md @@ -0,0 +1,286 @@ +## Semver Template: + +Since a `catalog template` is identified as an input schema which may be processed to generate a valid FBC, we can define a `semver template` as a schema which uses channel conventions to facilitate the auto-generation of channels along `semver` delimiters. + +[**DISCLAIMER:** since version build metadata [MUST be ignored when determining version precedence](https://semver.org) when using semver, rendering the template will result in an error if two bundles differ only by the build metadata.] + +### Schema Goals +The `semver template` must have: +- terse grammar to minimize creation/maintenance effort +- deterministic output +- simple channel promotion for maturing bundles +- demonstration of a common type of channel maturity model +- minor-version (Y-stream), major-version (X-stream) versioning optionality + +The resulting FBC must clearly indicate how generated channels relate to template entities + +### Schema Anatomy +For convenience and simplicity, this template currently supports hard-coded channel names `Candidate`, `Fast`, and `Stable`, in order of increasing channel stability. We leverage this relationship to calculate the default channel for the package. + +`GenerateMajorChannels` and `GenerateMinorChannels` dictate whether this template will generate X-stream or Y-stream channels (attributes can be set independently). If omitted, only minor (Y-stream) channels will be generated. + +Under each channel are a list of bundle image references which contribute to that channel. + +With the following (hypothetical) example we define a mock bundle which has 11 versions, represented across each of the channel types: +```yaml +Schema: olm.semver +GenerateMajorChannels: true +GenerateMinorChannels: true +Candidate: + Bundles: + - Image: quay.io/foo/olm:testoperator.v0.1.0 + - Image: quay.io/foo/olm:testoperator.v0.1.1 + - Image: quay.io/foo/olm:testoperator.v0.1.2 + - Image: quay.io/foo/olm:testoperator.v0.1.3 + - Image: quay.io/foo/olm:testoperator.v0.2.0 + - Image: quay.io/foo/olm:testoperator.v0.2.1 + - Image: quay.io/foo/olm:testoperator.v0.2.2 + - Image: quay.io/foo/olm:testoperator.v0.3.0 + - Image: quay.io/foo/olm:testoperator.v1.0.0 + - Image: quay.io/foo/olm:testoperator.v1.0.1 + - Image: quay.io/foo/olm:testoperator.v1.1.0 +Fast: + Bundles: + - Image: quay.io/foo/olm:testoperator.v0.2.1 + - Image: quay.io/foo/olm:testoperator.v0.2.2 + - Image: quay.io/foo/olm:testoperator.v0.3.0 + - Image: quay.io/foo/olm:testoperator.v1.0.1 + - Image: quay.io/foo/olm:testoperator.v1.1.0 +Stable: + Bundles: + - Image: quay.io/foo/olm:testoperator.v1.0.1 +``` +In this example, `Candidate` has the entire version range of bundles, `Fast` has a mix of older and more-recent versions, and `Stable` channel only has a single published entry. + +### CLI Tool Usage +``` +% ./bin/opm alpha render-template semver -h +Generate a file-based catalog from a single 'semver template' file +When FILE is '-' or not provided, the template is read from standard input + +Usage: + opm alpha render-template semver [FILE] [flags] + +Flags: + -h, --help help for semver + -o, --output string Output format (json|yaml|mermaid) (default "json") + +Global Flags: + --skip-tls-verify skip TLS certificate verification for container image registries while pulling bundles + --use-http use plain HTTP for container image registries while pulling bundles +``` + +Example command usage: +``` +# Example with file argument passed in +opm alpha render-template semver infile.semver.template.yaml + +# Example with no file argument passed in +opm alpha render-template semver -o yaml < infile.semver.template.yaml > outfile.yaml + +# Example with "-" as the file argument passed in +cat infile.semver.template.yaml | opm alpha render-template semver -o mermaid - +``` +Note that if the command is called without a file argument and nothing passed in on standard input, +the command will hang indefinitely. Either a file argument or file information passed +in on standard input is required by the command. + +With the template attribute `GenerateMajorChannels: true` resulting major channels from the command are (filtering out `olm.bundle` content): +```yaml +--- +defaultChannel: stable-v1 +name: testoperator +schema: olm.package +--- +entries: + - name: testoperator.v0.1.0 + - name: testoperator.v0.1.1 + - name: testoperator.v0.1.2 + - name: testoperator.v0.1.3 + skips: + - testoperator.v0.1.0 + - testoperator.v0.1.1 + - testoperator.v0.1.2 + - name: testoperator.v0.2.0 + - name: testoperator.v0.2.1 + - name: testoperator.v0.2.2 + replaces: testoperator.v0.1.3 + skips: + - testoperator.v0.1.0 + - testoperator.v0.1.1 + - testoperator.v0.1.2 + - testoperator.v0.2.0 + - testoperator.v0.2.1 + - name: testoperator.v0.3.0 + replaces: testoperator.v0.2.2 + skips: + - testoperator.v0.1.0 + - testoperator.v0.1.1 + - testoperator.v0.1.2 + - testoperator.v0.1.3 + - testoperator.v0.2.0 + - testoperator.v0.2.1 +name: candidate-v0 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.0.0 + - name: testoperator.v1.0.1 + skips: + - testoperator.v1.0.0 + - name: testoperator.v1.1.0 + replaces: testoperator.v1.0.1 + skips: + - testoperator.v1.0.0 +name: candidate-v1 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v0.2.1 + - name: testoperator.v0.2.2 + skips: + - testoperator.v0.2.1 + - name: testoperator.v0.3.0 + replaces: testoperator.v0.2.2 + skips: + - testoperator.v0.2.1 +name: fast-v0 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.0.1 + - name: testoperator.v1.1.0 + replaces: testoperator.v1.0.1 +name: fast-v1 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.0.1 +name: stable-v1 +package: testoperator +schema: olm.channel +``` + +We generated a channel for each template channel entity corresponding to each of the 0.\#.\#, 1.\#.\# major version ranges with skips to the head of the highest semver in a channel. We also generated a replaces edge to traverse across minor version transitions within each major channel. Finally, we generated an `olm.package` object, setting as default the most-stable channel head we created. This process will prefer `Stable` channel over `Fast`, over `Candidate` and then a higher bundle version over a lower version. +(Please note that the naming of the generated channels indicates the digits of significance for that channel. For example, `fast-v1` is a decomposed channel of the `fast` type which contains only major versions of contributing bundles matching `v1`.) + +For contrast, with the template attribute `GenerateMinorChannels: true` and running the command again (again skipping rendered bundle image output) we get a bunch more channels: +```yaml +--- +defaultChannel: stable-v1.0 +name: testoperator +schema: olm.package +--- +entries: + - name: testoperator.v0.1.0 + - name: testoperator.v0.1.1 + - name: testoperator.v0.1.2 + - name: testoperator.v0.1.3 + skips: + - testoperator.v0.1.0 + - testoperator.v0.1.1 + - testoperator.v0.1.2 +name: candidate-v0.1 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v0.2.0 + - name: testoperator.v0.2.1 + - name: testoperator.v0.2.2 + replaces: testoperator.v0.1.3 + skips: + - testoperator.v0.1.0 + - testoperator.v0.1.1 + - testoperator.v0.1.2 + - testoperator.v0.2.0 + - testoperator.v0.2.1 +name: candidate-v0.2 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v0.3.0 + replaces: testoperator.v0.2.2 + skips: + - testoperator.v0.1.0 + - testoperator.v0.1.1 + - testoperator.v0.1.2 + - testoperator.v0.1.3 + - testoperator.v0.2.0 + - testoperator.v0.2.1 +name: candidate-v0.3 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.0.0 + - name: testoperator.v1.0.1 + skips: + - testoperator.v1.0.0 +name: candidate-v1.0 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.1.0 + replaces: testoperator.v1.0.1 + skips: + - testoperator.v1.0.0 +name: candidate-v1.1 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v0.2.1 + - name: testoperator.v0.2.2 + skips: + - testoperator.v0.2.1 +name: fast-v0.2 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v0.3.0 + replaces: testoperator.v0.2.2 + skips: + - testoperator.v0.2.1 +name: fast-v0.3 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.0.1 +name: fast-v1.0 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.1.0 + replaces: testoperator.v1.0.1 +name: fast-v1.1 +package: testoperator +schema: olm.channel +--- +entries: + - name: testoperator.v1.0.1 +name: stable-v1.0 +package: testoperator +schema: olm.channel +``` +Here, a channel is generated for each template channel which differs by minor version, each channel has a `replaces` edge from the highest version entry in the predecessor channel, and the highest version entry in each channel also has a skips list composed of all lower version entries within the same minor (Y). Please note that at no time do we transgress across major-version boundaries with the channels, to be consistent with [the semver convention](https://semver.org/) for major versions, where the purpose is to make incompatible API changes. + + +### DEMOS + +#### Major Channel Generation + + +#### Minor Channel Generation + + + diff --git a/alpha/template/semver/major-version-demo.gif b/alpha/template/semver/major-version-demo.gif new file mode 100644 index 000000000..21d46519c Binary files /dev/null and b/alpha/template/semver/major-version-demo.gif differ diff --git a/alpha/template/semver/minor-version-demo.gif b/alpha/template/semver/minor-version-demo.gif new file mode 100644 index 000000000..fbe9bf1ac Binary files /dev/null and b/alpha/template/semver/minor-version-demo.gif differ diff --git a/alpha/template/semver/semver.go b/alpha/template/semver/semver.go new file mode 100644 index 000000000..afd7e898c --- /dev/null +++ b/alpha/template/semver/semver.go @@ -0,0 +1,467 @@ +package semver + +import ( + "context" + "fmt" + "io" + "sort" + + "github.com/blang/semver/v4" + "k8s.io/apimachinery/pkg/util/errors" + "sigs.k8s.io/yaml" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func (t Template) Render(ctx context.Context) (*declcfg.DeclarativeConfig, error) { + var out declcfg.DeclarativeConfig + + sv, err := readFile(t.Data) + if err != nil { + return nil, fmt.Errorf("render: unable to read file: %v", err) + } + + // nolint:prealloc + var cfgs []declcfg.DeclarativeConfig + + bundleDict := buildBundleList(*sv) + for b := range bundleDict { + c, err := t.RenderBundle(ctx, b) + if err != nil { + return nil, err + } + if len(c.Bundles) != 1 { + return nil, fmt.Errorf("bundle reference %q resulted in %d bundles, expected 1", b, len(c.Bundles)) + } + bundleDict[b] = c.Bundles[0].Image + cfgs = append(cfgs, *c) + } + out = *combineConfigs(cfgs) + + if len(out.Bundles) == 0 { + return nil, fmt.Errorf("render: no bundles specified or no bundles could be rendered") + } + + channelBundleVersions, err := sv.getVersionsFromStandardChannels(&out, bundleDict) + if err != nil { + return nil, fmt.Errorf("render: unable to post-process bundle info: %v", err) + } + + channels := sv.generateChannels(channelBundleVersions) + out.Channels = channels + out.Packages[0].DefaultChannel = sv.defaultChannel + + return &out, nil +} + +func buildBundleList(t semverTemplate) map[string]string { + dict := make(map[string]string) + for _, bl := range []semverTemplateChannelBundles{t.Candidate, t.Fast, t.Stable} { + for _, b := range bl.Bundles { + if _, ok := dict[b.Image]; !ok { + dict[b.Image] = b.Image + } + } + } + return dict +} + +func readFile(reader io.Reader) (*semverTemplate, error) { + data, err := io.ReadAll(reader) + if err != nil { + return nil, err + } + + sv := semverTemplate{} + if err := yaml.UnmarshalStrict(data, &sv); err != nil { + return nil, err + } + + if sv.Schema != schema { + return nil, fmt.Errorf("readFile: input file has unknown schema, should be %q", schema) + } + + // if no generate option is selected, default to GenerateMinorChannels + if !sv.GenerateMajorChannels && !sv.GenerateMinorChannels { + sv.GenerateMinorChannels = true + } + + // for default channel preference, + // if un-set, default to align to the selected generate option + // if set, error out if we mismatch the two + switch sv.DefaultChannelTypePreference { + case defaultStreamType: + if sv.GenerateMinorChannels { + sv.DefaultChannelTypePreference = minorStreamType + } else if sv.GenerateMajorChannels { + sv.DefaultChannelTypePreference = majorStreamType + } + case minorStreamType: + if !sv.GenerateMinorChannels { + return nil, fmt.Errorf("schema attribute mismatch: DefaultChannelTypePreference set to 'minor' doesn't make sense if not generating minor-version channels") + } + case majorStreamType: + if !sv.GenerateMajorChannels { + return nil, fmt.Errorf("schema attribute mismatch: DefaultChannelTypePreference set to 'major' doesn't make sense if not generating major-version channels") + } + default: + return nil, fmt.Errorf("unknown DefaultChannelTypePreference: %q\nValid values are 'major' or 'minor'", sv.DefaultChannelTypePreference) + } + + return &sv, nil +} + +func (sv *semverTemplate) getVersionsFromStandardChannels(cfg *declcfg.DeclarativeConfig, bundleDict map[string]string) (*bundleVersions, error) { + versions := bundleVersions{} + + bdm, err := sv.getVersionsFromChannel(sv.Candidate.Bundles, bundleDict, cfg) + if err != nil { + return nil, err + } + if err = validateVersions(&bdm); err != nil { + return nil, err + } + versions[candidateChannelArchetype] = bdm + + bdm, err = sv.getVersionsFromChannel(sv.Fast.Bundles, bundleDict, cfg) + if err != nil { + return nil, err + } + if err = validateVersions(&bdm); err != nil { + return nil, err + } + versions[fastChannelArchetype] = bdm + + bdm, err = sv.getVersionsFromChannel(sv.Stable.Bundles, bundleDict, cfg) + if err != nil { + return nil, err + } + if err = validateVersions(&bdm); err != nil { + return nil, err + } + versions[stableChannelArchetype] = bdm + + return &versions, nil +} + +func (sv *semverTemplate) getVersionsFromChannel(semverBundles []semverTemplateBundleEntry, bundleDict map[string]string, cfg *declcfg.DeclarativeConfig) (map[string]semver.Version, error) { + entries := make(map[string]semver.Version) + + // we iterate over the channel bundles from the template, to: + // - identify if any required bundles for the channel are missing/not rendered/otherwise unavailable + // - maintain the channel-bundle relationship as we map from un-rendered semver template bundles to rendered bundles in `entries` which is accumulated by the caller + // in a per-channel structure to which we can safely refer when generating/linking channels + for _, semverBundle := range semverBundles { + // test if the bundle specified in the template is present in the successfully-rendered bundles + index := 0 + for index < len(cfg.Bundles) { + if cfg.Bundles[index].Image == bundleDict[semverBundle.Image] { + break + } + index++ + } + if index == len(cfg.Bundles) { + return nil, fmt.Errorf("supplied bundle image name %q not found in rendered bundle images", semverBundle.Image) + } + b := cfg.Bundles[index] + + props, err := property.Parse(b.Properties) + if err != nil { + return nil, fmt.Errorf("parse properties for bundle %q: %v", b.Name, err) + } + if len(props.Packages) != 1 { + return nil, fmt.Errorf("bundle %q has multiple %q properties, expected exactly 1", b.Name, property.TypePackage) + } + v, err := semver.Parse(props.Packages[0].Version) + if err != nil { + return nil, fmt.Errorf("bundle %q has invalid version %q: %v", b.Name, props.Packages[0].Version, err) + } + + // package name detection + if sv.pkg != "" { + // if we have a known package name, then ensure all subsequent packages match + if props.Packages[0].PackageName != sv.pkg { + return nil, fmt.Errorf("bundle %q does not belong to this package: %q", props.Packages[0].PackageName, sv.pkg) + } + } else { + // else cache the first + p := newPackage(props.Packages[0].PackageName) + cfg.Packages = append(cfg.Packages, *p) + sv.pkg = props.Packages[0].PackageName + } + + if _, ok := entries[b.Name]; ok { + return nil, fmt.Errorf("duplicate bundle name %q", b.Name) + } + + entries[b.Name] = v + } + + return entries, nil +} + +// generates an unlinked channel for each channel as per the input template config (major || minor), then link up the edges of the set of channels so that: +// - for minor version increase, the new edge replaces the previous +// - (for major channels) iterating to a new minor version channel (traversing between Y-streams) creates a 'replaces' edge between the predecessor and successor bundles +// - within the same minor version (Y-stream), the head of the channel should have a 'skips' encompassing all lesser Y.Z versions of the bundle enumerated in the template. +// along the way, uses a highwaterChannel marker to identify the "most stable" channel head to be used as the default channel for the generated package + +func (sv *semverTemplate) generateChannels(semverChannels *bundleVersions) []declcfg.Channel { + outChannels := []declcfg.Channel{} + + // sort the channel archetypes in ascending order so we can traverse the bundles in order of + // their source channel's priority + // nolint:prealloc + var archetypesByPriority []channelArchetype + for k := range channelPriorities { + archetypesByPriority = append(archetypesByPriority, k) + } + sort.Sort(byChannelPriority(archetypesByPriority)) + + // set to the least-priority channel + hwc := highwaterChannel{archetype: archetypesByPriority[0], version: semver.Version{Major: 0, Minor: 0}} + + unlinkedChannels := make(map[string]*declcfg.Channel) + + for _, archetype := range archetypesByPriority { + bundles := (*semverChannels)[archetype] + // skip channel if empty + if len(bundles) == 0 { + continue + } + + // sort the bundle names according to their semver, so we can walk in ascending order + bundleNamesByVersion := []string{} + for b := range bundles { + bundleNamesByVersion = append(bundleNamesByVersion, b) + } + sort.Slice(bundleNamesByVersion, func(i, j int) bool { + return bundles[bundleNamesByVersion[i]].LT(bundles[bundleNamesByVersion[j]]) + }) + + // for each bundle (by version): + // for each of Major/Minor setting (since they're independent) + // retrieve the existing channel object, or create a channel (by criteria major/minor) if one doesn't exist + // add a new edge entry based on the bundle name + // save the channel name --> channel archetype mapping + // test the channel object for 'more stable' than previous best + for _, bundleName := range bundleNamesByVersion { + // a dodge to avoid duplicating channel processing body; accumulate a map of the channels which need creating from the bundle + // we need to associate by kind so we can partition the resulting entries + channelNameKeys := make(map[streamType]string) + if sv.GenerateMajorChannels { + channelNameKeys[majorStreamType] = channelNameFromMajor(archetype, bundles[bundleName]) + } + if sv.GenerateMinorChannels { + channelNameKeys[minorStreamType] = channelNameFromMinor(archetype, bundles[bundleName]) + } + + for cKey, cName := range channelNameKeys { + ch, ok := unlinkedChannels[cName] + if !ok { + ch = newChannel(sv.pkg, cName) + + unlinkedChannels[cName] = ch + + hwcCandidate := highwaterChannel{archetype: archetype, kind: cKey, version: bundles[bundleName], name: cName} + if hwcCandidate.gt(&hwc, sv.DefaultChannelTypePreference) { + hwc = hwcCandidate + } + } + ch.Entries = append(ch.Entries, declcfg.ChannelEntry{Name: bundleName}) + } + } + } + + // save off the name of the high-water-mark channel for the default for this package + sv.defaultChannel = hwc.name + + outChannels = append(outChannels, sv.linkChannels(unlinkedChannels, semverChannels)...) + + return outChannels +} + +func (sv *semverTemplate) linkChannels(unlinkedChannels map[string]*declcfg.Channel, harvestedVersions *bundleVersions) []declcfg.Channel { + channels := []declcfg.Channel{} + + // bundle --> version lookup + bundleVersions := make(map[string]semver.Version) + for _, vs := range *harvestedVersions { + for b, v := range vs { + if _, ok := bundleVersions[b]; !ok { + bundleVersions[b] = v + } + } + } + + for _, channel := range unlinkedChannels { + entries := &channel.Entries + sort.Slice(*entries, func(i, j int) bool { + return bundleVersions[(*entries)[i].Name].LT(bundleVersions[(*entries)[j].Name]) + }) + + // "inchworm" through the sorted entries, iterating curEdge but extending yProbe to the next Y-transition + // then catch up curEdge to yProbe as 'skips', and repeat until we reach the end of the entries + // finally, because the inchworm will always fail to pick up the last Y-transition, we test for it and link it up as a 'replaces' + curEdge, yProbe := 0, 0 + zmaxQueue := "" + entryCount := len(*entries) + + for curEdge < entryCount { + for yProbe < entryCount { + curVersion := bundleVersions[(*entries)[curEdge].Name] + yProbeVersion := bundleVersions[(*entries)[yProbe].Name] + if getMinorVersion(yProbeVersion).EQ(getMinorVersion(curVersion)) { + yProbe += 1 + } else { + break + } + } + // if yProbe crossed a threshold, the previous entry is the last of the previous Y-stream + preChangeIndex := yProbe - 1 + + if curEdge != yProbe { + if zmaxQueue != "" { + // add skips edge to allow skipping over y iterations within an x stream + (*entries)[preChangeIndex].Skips = append((*entries)[preChangeIndex].Skips, zmaxQueue) + (*entries)[preChangeIndex].Replaces = zmaxQueue + } + zmaxQueue = (*entries)[preChangeIndex].Name + } + for curEdge < preChangeIndex { + // add skips edges to y-1 from z < y + (*entries)[preChangeIndex].Skips = append((*entries)[preChangeIndex].Skips, (*entries)[curEdge].Name) + curEdge += 1 + } + curEdge += 1 + yProbe = curEdge + 1 + } + // since probe will always fail to pick up a y-change in the last item, test for it + if entryCount > 1 { + penultimateEntry := &(*entries)[len(*entries)-2] + ultimateEntry := &(*entries)[len(*entries)-1] + penultimateVersion := bundleVersions[penultimateEntry.Name] + ultimateVersion := bundleVersions[ultimateEntry.Name] + if ultimateVersion.Minor != penultimateVersion.Minor { + ultimateEntry.Replaces = penultimateEntry.Name + } + } + channels = append(channels, *channel) + } + + return channels +} + +func channelNameFromMinor(prefix channelArchetype, version semver.Version) string { + return fmt.Sprintf("%s-v%d.%d", prefix, version.Major, version.Minor) +} + +func channelNameFromMajor(prefix channelArchetype, version semver.Version) string { + return fmt.Sprintf("%s-v%d", prefix, version.Major) +} + +func newPackage(name string) *declcfg.Package { + return &declcfg.Package{ + Schema: "olm.package", + Name: name, + DefaultChannel: "", + } +} + +func newChannel(pkgName string, chName string) *declcfg.Channel { + return &declcfg.Channel{ + Schema: "olm.channel", + Name: chName, + Package: pkgName, + Entries: []declcfg.ChannelEntry{}, + } +} + +func combineConfigs(cfgs []declcfg.DeclarativeConfig) *declcfg.DeclarativeConfig { + out := &declcfg.DeclarativeConfig{} + for _, in := range cfgs { + out.Merge(&in) + } + return out +} + +func getMinorVersion(v semver.Version) semver.Version { + return semver.Version{ + Major: v.Major, + Minor: v.Minor, + } +} + +// nolint:unused +func getMajorVersion(v semver.Version) semver.Version { + return semver.Version{ + Major: v.Major, + } +} + +func withoutBuildMetadataConflict(versions *map[string]semver.Version) error { + errs := []error{} + + // using the stringified semver because the semver package generates deterministic representations, + // and because the semver.Version contains slice fields which make it unsuitable as a map key + // stringified-semver.Version ==> incidence count + seen := make(map[string]int) + for b := range *versions { + stripped := stripBuildMetadata((*versions)[b]) + if _, ok := seen[stripped]; !ok { + seen[stripped] = 1 + } else { + seen[stripped] = seen[stripped] + 1 + errs = append(errs, fmt.Errorf("bundle version %q cannot be compared to %q", (*versions)[b].String(), stripped)) + } + } + + if len(errs) != 0 { + return fmt.Errorf("encountered bundle versions which differ only by build metadata, which cannot be ordered: %v", errors.NewAggregate(errs)) + } + + return nil +} + +func validateVersions(versions *map[string]semver.Version) error { + // short-circuit if empty, since that is not an error + if len(*versions) == 0 { + return nil + } + return withoutBuildMetadataConflict(versions) +} + +// strips out the build metadata from a semver.Version and then stringifies it to make it suitable for collision detection +func stripBuildMetadata(v semver.Version) string { + v.Build = nil + return v.String() +} + +// prefer (in descending order of preference): +// - higher-rank archetype, +// - semver version, +// - a channel type matching the set preference, or +// - a 'better' (higher value) channel type +func (h *highwaterChannel) gt(ih *highwaterChannel, pref streamType) bool { + if channelPriorities[h.archetype] != channelPriorities[ih.archetype] { + return channelPriorities[h.archetype] > channelPriorities[ih.archetype] + } + if h.version.NE(ih.version) { + return h.version.GT(ih.version) + } + if h.kind != ih.kind { + if h.kind == pref { + return true + } + if ih.kind == pref { + return false + } + return h.kind.gt((*ih).kind) + } + return false +} + +func (t streamType) gt(in streamType) bool { + return streamTypePriorities[t] > streamTypePriorities[in] +} diff --git a/alpha/template/semver/semver_test.go b/alpha/template/semver/semver_test.go new file mode 100644 index 000000000..68cd84e66 --- /dev/null +++ b/alpha/template/semver/semver_test.go @@ -0,0 +1,713 @@ +package semver + +import ( + "fmt" + "strings" + "testing" + + "github.com/blang/semver/v4" + "github.com/stretchr/testify/require" + + "github.com/operator-framework/operator-registry/alpha/declcfg" + "github.com/operator-framework/operator-registry/alpha/property" +) + +func TestLinkChannels(t *testing.T) { + // type bundleVersions map[string]map[string]semver.Version // e.g. d["stable"]["example-operator.v1.0.0"] = 1.0.0 + channelOperatorVersions := bundleVersions{ + "stable": { + "a-v0.1.0": semver.MustParse("0.1.0"), + "a-v0.1.1": semver.MustParse("0.1.1"), + "a-v1.1.0": semver.MustParse("1.1.0"), + "a-v1.2.1": semver.MustParse("1.2.1"), + "a-v1.3.1": semver.MustParse("1.3.1"), + "a-v2.1.0": semver.MustParse("2.1.0"), + "a-v1.3.1-beta": semver.MustParse(("1.3.1-beta")), + "a-v2.1.1": semver.MustParse("2.1.1"), + "a-v2.3.1": semver.MustParse("2.3.1"), + "a-v2.3.2": semver.MustParse("2.3.2"), + "a-v3.1.0": semver.MustParse("3.1.0"), + "a-v3.1.1": semver.MustParse("3.1.1"), + "a-v1.3.1-alpha": semver.MustParse("1.3.1-alpha"), + "a-v1.4.1": semver.MustParse("1.4.1"), + "a-v1.4.1-beta1": semver.MustParse("1.4.1-beta1"), + "a-v1.4.1-beta2": semver.MustParse("1.4.1-beta2"), + }, + } + + majorGeneratedUnlinkedChannels := map[string]*declcfg.Channel{ + "stable-v0": { + Schema: "olm.channel", + Name: "stable-v0", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v0.1.0"}, + {Name: "a-v0.1.1"}, + }, + }, + "stable-v1": { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0"}, + {Name: "a-v1.2.1"}, + {Name: "a-v1.3.1"}, + }, + }, + "stable-v2": { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0"}, + {Name: "a-v2.1.1"}, + {Name: "a-v2.3.1"}, + {Name: "a-v2.3.2"}, + }, + }, + } + + majorGeneratedUnlinkedChannelsLastXChange := map[string]*declcfg.Channel{ + "stable-v0": { + Schema: "olm.channel", + Name: "stable-v0", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v0.1.0"}, + {Name: "a-v0.1.1"}, + }, + }, + "stable-v1": { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0"}, + {Name: "a-v1.2.1"}, + {Name: "a-v1.3.1"}, + }, + }, + "stable-v2": { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0"}, + }, + }, + } + + majorGeneratedUnlinkedChannelsLastArchChange := map[string]*declcfg.Channel{ + "candidate-v2": { + Schema: "olm.channel", + Name: "candidate-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.3.2"}, + }, + }, + "stable-v1": { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0"}, + {Name: "a-v1.2.1"}, + {Name: "a-v1.3.1"}, + }, + }, + "stable-v2": { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0"}, + {Name: "a-v2.1.1"}, + {Name: "a-v2.3.1"}, + }, + }, + } + + tests := []struct { + name string + unlinkedChannels map[string]*declcfg.Channel + generateMinorChannels bool + generateMajorChannels bool + out []declcfg.Channel + }{ + { + name: "No edges between successive major channels", + unlinkedChannels: majorGeneratedUnlinkedChannels, + generateMinorChannels: false, + generateMajorChannels: true, + out: []declcfg.Channel{ + { + Schema: "olm.channel", + Name: "stable-v0", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v0.1.0", Replaces: ""}, + {Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0", Replaces: ""}, + {Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}}, + {Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0", Replaces: ""}, + {Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}}, + {Name: "a-v2.3.1", Replaces: ""}, + {Name: "a-v2.3.2", Replaces: "a-v2.1.1", Skips: []string{"a-v2.1.1", "a-v2.3.1"}}, + }, + }, + }, + }, + { + name: "No edges between successive major channels where last edge is X change", + unlinkedChannels: majorGeneratedUnlinkedChannelsLastXChange, + generateMinorChannels: false, + generateMajorChannels: true, + out: []declcfg.Channel{ + { + Schema: "olm.channel", + Name: "stable-v0", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v0.1.0", Replaces: ""}, + {Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0", Replaces: ""}, + {Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}}, + {Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0", Replaces: ""}, + }, + }, + }, + }, + { + name: "No edges between successive major channels where last edge is archetype change", + unlinkedChannels: majorGeneratedUnlinkedChannelsLastArchChange, + generateMinorChannels: false, + generateMajorChannels: true, + out: []declcfg.Channel{ + { + Schema: "olm.channel", + Name: "candidate-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.3.2", Replaces: ""}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0", Replaces: ""}, + {Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}}, + {Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0", Replaces: ""}, + {Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}}, + {Name: "a-v2.3.1", Replaces: "a-v2.1.1", Skips: []string{"a-v2.1.1"}}, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sv := &semverTemplate{pkg: "a", GenerateMajorChannels: tt.generateMajorChannels, GenerateMinorChannels: tt.generateMinorChannels} + require.ElementsMatch(t, tt.out, sv.linkChannels(tt.unlinkedChannels, &channelOperatorVersions)) + }) + } +} + +func TestGenerateChannels(t *testing.T) { + // type bundleVersions map[string]map[string]semver.Version // e.g. d["stable"]["example-operator.v1.0.0"] = 1.0.0 + channelOperatorVersions := bundleVersions{ + "stable": { + "a-v0.1.0": semver.MustParse("0.1.0"), + "a-v0.1.1": semver.MustParse("0.1.1"), + "a-v1.1.0": semver.MustParse("1.1.0"), + "a-v1.2.1": semver.MustParse("1.2.1"), + "a-v1.3.1": semver.MustParse("1.3.1"), + "a-v2.1.0": semver.MustParse("2.1.0"), + "a-v1.3.1-beta": semver.MustParse(("1.3.1-beta")), + "a-v2.1.1": semver.MustParse("2.1.1"), + "a-v2.3.1": semver.MustParse("2.3.1"), + "a-v2.3.2": semver.MustParse("2.3.2"), + "a-v3.1.0": semver.MustParse("3.1.0"), + "a-v3.1.1": semver.MustParse("3.1.1"), + "a-v1.3.1-alpha": semver.MustParse("1.3.1-alpha"), + "a-v1.4.1": semver.MustParse("1.4.1"), + "a-v1.4.1-beta1": semver.MustParse("1.4.1-beta1"), + "a-v1.4.1-beta2": semver.MustParse("1.4.1-beta2"), + }, + } + + majorLinkedChannels := []declcfg.Channel{ + { + Schema: "olm.channel", + Name: "stable-v0", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v0.1.0", Replaces: ""}, + {Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0", Replaces: ""}, + {Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}}, + {Name: "a-v1.3.1-alpha", Replaces: ""}, + {Name: "a-v1.3.1-beta", Replaces: ""}, + {Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1", "a-v1.3.1-alpha", "a-v1.3.1-beta"}}, + {Name: "a-v1.4.1-beta1", Replaces: ""}, + {Name: "a-v1.4.1-beta2", Replaces: ""}, + {Name: "a-v1.4.1", Replaces: "a-v1.3.1", Skips: []string{"a-v1.3.1", "a-v1.4.1-beta1", "a-v1.4.1-beta2"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0", Replaces: ""}, + {Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}}, + {Name: "a-v2.3.1", Replaces: ""}, + {Name: "a-v2.3.2", Replaces: "a-v2.1.1", Skips: []string{"a-v2.1.1", "a-v2.3.1"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v3", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v3.1.0", Replaces: ""}, + {Name: "a-v3.1.1", Replaces: "", Skips: []string{"a-v3.1.0"}}, + }, + }, + } + + minorLinkedChannels := []declcfg.Channel{ + { + Schema: "olm.channel", + Name: "stable-v0.1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v0.1.0", Replaces: ""}, + {Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1.1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.1.0", Replaces: ""}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1.2", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.2.1", Replaces: ""}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1.3", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.3.1-alpha", Replaces: ""}, + {Name: "a-v1.3.1-beta", Replaces: ""}, + {Name: "a-v1.3.1", Replaces: "", Skips: []string{"a-v1.3.1-alpha", "a-v1.3.1-beta"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v1.4", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v1.4.1-beta1", Replaces: ""}, + {Name: "a-v1.4.1-beta2", Replaces: ""}, + {Name: "a-v1.4.1", Replaces: "", Skips: []string{"a-v1.4.1-beta1", "a-v1.4.1-beta2"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v2.1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.1.0", Replaces: ""}, + {Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v2.3", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v2.3.1", Replaces: ""}, + {Name: "a-v2.3.2", Replaces: "", Skips: []string{"a-v2.3.1"}}, + }, + }, + { + Schema: "olm.channel", + Name: "stable-v3.1", + Package: "a", + Entries: []declcfg.ChannelEntry{ + {Name: "a-v3.1.0", Replaces: ""}, + {Name: "a-v3.1.1", Replaces: "", Skips: []string{"a-v3.1.0"}}, + }, + }, + } + + var combinedLinkedChannels []declcfg.Channel + combinedLinkedChannels = append(combinedLinkedChannels, minorLinkedChannels...) + combinedLinkedChannels = append(combinedLinkedChannels, majorLinkedChannels...) + + tests := []struct { + name string + generateMinorChannels bool + generateMajorChannels bool + defaultChannel string + channelTypePreference streamType + out []declcfg.Channel + }{ + { + name: "Edges between minor channels", + generateMinorChannels: true, + generateMajorChannels: false, + defaultChannel: "stable-v3.1", + channelTypePreference: minorStreamType, + out: minorLinkedChannels, + }, + { + name: "No edges between major channels", + generateMinorChannels: false, + generateMajorChannels: true, + defaultChannel: "stable-v3", + channelTypePreference: majorStreamType, + out: majorLinkedChannels, + }, + { + name: "Preference for minor default channel", + generateMinorChannels: true, + generateMajorChannels: true, + defaultChannel: "stable-v3.1", + channelTypePreference: minorStreamType, + out: combinedLinkedChannels, + }, + { + name: "Preference for major default channel", + generateMinorChannels: true, + generateMajorChannels: true, + defaultChannel: "stable-v3", + channelTypePreference: majorStreamType, + out: combinedLinkedChannels, + }, + { + name: "Mismatch generate/preference minor/major default channel", + generateMinorChannels: true, + generateMajorChannels: false, + defaultChannel: "stable-v3.1", + channelTypePreference: majorStreamType, + out: minorLinkedChannels, + }, + { + name: "Mismatch generate/preference major/minor default channel", + generateMinorChannels: false, + generateMajorChannels: true, + defaultChannel: "stable-v3", + channelTypePreference: minorStreamType, + out: majorLinkedChannels, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sv := &semverTemplate{GenerateMajorChannels: tt.generateMajorChannels, GenerateMinorChannels: tt.generateMinorChannels, pkg: "a", DefaultChannelTypePreference: tt.channelTypePreference} + out := sv.generateChannels(&channelOperatorVersions) + require.ElementsMatch(t, tt.out, out) + require.Equal(t, tt.defaultChannel, sv.defaultChannel) + }) + } +} + +func TestGetVersionsFromStandardChannel(t *testing.T) { + tests := []struct { + name string + sv semverTemplate + outVersions bundleVersions + dc declcfg.DeclarativeConfig + }{ + { + name: "sunny day case", + sv: semverTemplate{ + Stable: semverTemplateChannelBundles{ + []semverTemplateBundleEntry{ + {Image: "repo/origin/a-v0.1.0"}, + {Image: "repo/origin/a-v0.1.1"}, + {Image: "repo/origin/a-v1.1.0"}, + {Image: "repo/origin/a-v1.2.1"}, + {Image: "repo/origin/a-v1.3.1"}, + {Image: "repo/origin/a-v2.1.0"}, + {Image: "repo/origin/a-v2.1.1"}, + {Image: "repo/origin/a-v2.3.1"}, + {Image: "repo/origin/a-v2.3.2"}, + {Image: "repo/origin/a-v1.3.1-alpha"}, + }, + }, + }, + outVersions: bundleVersions{ + "candidate": map[string]semver.Version{}, + "fast": map[string]semver.Version{}, + "stable": { + "a-v0.1.0": semver.MustParse("0.1.0"), + "a-v0.1.1": semver.MustParse("0.1.1"), + "a-v1.1.0": semver.MustParse("1.1.0"), + "a-v1.2.1": semver.MustParse("1.2.1"), + "a-v1.3.1": semver.MustParse("1.3.1"), + "a-v2.1.0": semver.MustParse("2.1.0"), + "a-v2.1.1": semver.MustParse("2.1.1"), + "a-v2.3.1": semver.MustParse("2.3.1"), + "a-v2.3.2": semver.MustParse("2.3.2"), + "a-v1.3.1-alpha": semver.MustParse("1.3.1-alpha"), + }, + }, + dc: declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "a", + }, + }, + Bundles: []declcfg.Bundle{ + {Schema: "olm.bundle", Image: "repo/origin/a-v0.1.0", Name: "a-v0.1.0", Properties: []property.Property{property.MustBuildPackage("a", "0.1.0")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v0.1.1", Name: "a-v0.1.1", Properties: []property.Property{property.MustBuildPackage("a", "0.1.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.1.0", Name: "a-v1.1.0", Properties: []property.Property{property.MustBuildPackage("a", "1.1.0")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.2.1", Name: "a-v1.2.1", Properties: []property.Property{property.MustBuildPackage("a", "1.2.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha", Name: "a-v1.3.1-alpha", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1", Name: "a-v1.3.1", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.1.0", Name: "a-v2.1.0", Properties: []property.Property{property.MustBuildPackage("a", "2.1.0")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.1.1", Name: "a-v2.1.1", Properties: []property.Property{property.MustBuildPackage("a", "2.1.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.3.1", Name: "a-v2.3.1", Properties: []property.Property{property.MustBuildPackage("a", "2.3.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.3.2", Name: "a-v2.3.2", Properties: []property.Property{property.MustBuildPackage("a", "2.3.2")}}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + iosv := tt.sv + versions, err := iosv.getVersionsFromStandardChannels(&tt.dc, buildBundleList(tt.sv)) + require.NoError(t, err) + require.EqualValues(t, tt.outVersions, *versions) + require.EqualValues(t, "a", iosv.pkg) // verify that we learned the package name and stashed it in the receiver + }) + } +} + +func TestBailOnVersionBuildMetadata(t *testing.T) { + sv := semverTemplate{ + Stable: semverTemplateChannelBundles{ + []semverTemplateBundleEntry{ + {Image: "repo/origin/a-v0.1.0"}, + {Image: "repo/origin/a-v0.1.1"}, + {Image: "repo/origin/a-v1.1.0"}, + {Image: "repo/origin/a-v1.2.1"}, + {Image: "repo/origin/a-v1.3.1"}, + {Image: "repo/origin/a-v2.1.0"}, + {Image: "repo/origin/a-v2.1.1"}, + {Image: "repo/origin/a-v2.3.1"}, + {Image: "repo/origin/a-v2.3.2"}, + {Image: "repo/origin/a-v1.3.1-alpha"}, + {Image: "repo/origin/a-v1.3.1-alpha+2001Jan21"}, + {Image: "repo/origin/a-v1.3.1-alpha+2003May06"}, + }, + }, + } + + dc := declcfg.DeclarativeConfig{ + Packages: []declcfg.Package{ + { + Schema: "olm.package", + Name: "a", + }, + }, + Bundles: []declcfg.Bundle{ + {Schema: "olm.bundle", Image: "repo/origin/a-v0.1.0", Name: "a-v0.1.0", Properties: []property.Property{property.MustBuildPackage("a", "0.1.0")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v0.1.1", Name: "a-v0.1.1", Properties: []property.Property{property.MustBuildPackage("a", "0.1.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.1.0", Name: "a-v1.1.0", Properties: []property.Property{property.MustBuildPackage("a", "1.1.0")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.2.1", Name: "a-v1.2.1", Properties: []property.Property{property.MustBuildPackage("a", "1.2.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha", Name: "a-v1.3.1-alpha", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha+2001Jan21", Name: "a-v1.3.1-alpha+2001Jan21", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha+2001Jan21")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1", Name: "a-v1.3.1", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.1.0", Name: "a-v2.1.0", Properties: []property.Property{property.MustBuildPackage("a", "2.1.0")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.1.1", Name: "a-v2.1.1", Properties: []property.Property{property.MustBuildPackage("a", "2.1.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.3.1", Name: "a-v2.3.1", Properties: []property.Property{property.MustBuildPackage("a", "2.3.1")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v2.3.2", Name: "a-v2.3.2", Properties: []property.Property{property.MustBuildPackage("a", "2.3.2")}}, + {Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha+2003May06", Name: "a-v1.3.1-alpha+2003May06", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha+2003May06")}}, + }, + } + + t.Run("Abort on unorderable build metadata version data", func(t *testing.T) { + _, err := sv.getVersionsFromStandardChannels(&dc, buildBundleList(sv)) + require.Error(t, err) + }) +} + +func TestReadFile(t *testing.T) { + templateFstr := `--- +schema: olm.semver +generateMajorChannels: %s +generateMinorChannels: %s +defaultChannelTypePreference: %s +candidate: + bundles: + - image: quay.io/foo/olm:testoperator.v0.1.0 + - image: quay.io/foo/olm:testoperator.v0.1.1 + - image: quay.io/foo/olm:testoperator.v0.1.2 + - image: quay.io/foo/olm:testoperator.v0.1.3 + - image: quay.io/foo/olm:testoperator.v0.2.0 + - image: quay.io/foo/olm:testoperator.v0.2.1 + - image: quay.io/foo/olm:testoperator.v0.2.2 + - image: quay.io/foo/olm:testoperator.v0.3.0 + - image: quay.io/foo/olm:testoperator.v1.0.0 + - image: quay.io/foo/olm:testoperator.v1.0.1 + - image: quay.io/foo/olm:testoperator.v1.1.0 +fast: + bundles: + - image: quay.io/foo/olm:testoperator.v0.2.1 + - image: quay.io/foo/olm:testoperator.v0.2.2 + - image: quay.io/foo/olm:testoperator.v0.3.0 + - image: quay.io/foo/olm:testoperator.v1.0.1 + - image: quay.io/foo/olm:testoperator.v1.1.0 +stable: + bundles: + - image: quay.io/foo/olm:testoperator.v1.0.1 +` + + type testCase struct { + name string + input string + assertions func(*testing.T, *semverTemplate, error) + } + testCases := []testCase{ + { + name: "valid", + input: fmt.Sprintf(templateFstr, "true", "true", "minor"), + assertions: func(t *testing.T, template *semverTemplate, err error) { + require.NotNil(t, template) + require.NoError(t, err) + }, + }, + { + name: "unknown channel prefix", + input: `--- +schema: olm.semver +generateMajorChannels: true +generateMinorChannels: true +candidate: + bundles: + - image: quay.io/foo/olm:testoperator.v0.1.0 + - image: quay.io/foo/olm:testoperator.v0.1.1 + - image: quay.io/foo/olm:testoperator.v0.1.2 + - image: quay.io/foo/olm:testoperator.v0.1.3 + - image: quay.io/foo/olm:testoperator.v0.2.0 + - image: quay.io/foo/olm:testoperator.v0.2.1 + - image: quay.io/foo/olm:testoperator.v0.2.2 + - image: quay.io/foo/olm:testoperator.v0.3.0 + - image: quay.io/foo/olm:testoperator.v1.0.0 + - image: quay.io/foo/olm:testoperator.v1.0.1 + - image: quay.io/foo/olm:testoperator.v1.1.0 +fast: + bundles: + - image: quay.io/foo/olm:testoperator.v0.2.1 + - image: quay.io/foo/olm:testoperator.v0.2.2 + - image: quay.io/foo/olm:testoperator.v0.3.0 + - image: quay.io/foo/olm:testoperator.v1.0.1 + - image: quay.io/foo/olm:testoperator.v1.1.0 +stable: + bundles: + - image: quay.io/foo/olm:testoperator.v1.0.1 +invalid: + bundles: + - image: quay.io/foo/olm:testoperator.v1.0.1 +`, + assertions: func(t *testing.T, template *semverTemplate, err error) { + require.Nil(t, template) + require.EqualError(t, err, `error unmarshaling JSON: while decoding JSON: json: unknown field "invalid"`) + }, + }, + { + name: "generate/default mismatch, minor/major", + input: fmt.Sprintf(templateFstr, "true", "false", "minor"), + assertions: func(t *testing.T, template *semverTemplate, err error) { + require.Nil(t, template) + require.ErrorContains(t, err, "schema attribute mismatch") + }, + }, + { + name: "generate/default mismatch, major/minor", + input: fmt.Sprintf(templateFstr, "false", "true", "major"), + assertions: func(t *testing.T, template *semverTemplate, err error) { + require.Nil(t, template) + require.ErrorContains(t, err, "schema attribute mismatch") + }, + }, + { + name: "unknown defaultchanneltypepreference", + input: fmt.Sprintf(templateFstr, "false", "true", "foo"), + assertions: func(t *testing.T, template *semverTemplate, err error) { + require.Nil(t, template) + require.ErrorContains(t, err, "unknown DefaultChannelTypePreference") + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + sv, err := readFile(strings.NewReader(tc.input)) + tc.assertions(t, sv, err) + }) + } +} diff --git a/alpha/template/semver/types.go b/alpha/template/semver/types.go new file mode 100644 index 000000000..b0846a64f --- /dev/null +++ b/alpha/template/semver/types.go @@ -0,0 +1,84 @@ +package semver + +import ( + "context" + "io" + + "github.com/blang/semver/v4" + + "github.com/operator-framework/operator-registry/alpha/declcfg" +) + +// data passed into this module externally +type Template struct { + Data io.Reader + RenderBundle func(context.Context, string) (*declcfg.DeclarativeConfig, error) +} + +// IO structs -- BEGIN +type semverTemplateBundleEntry struct { + Image string `json:"image,omitempty"` +} + +type semverTemplateChannelBundles struct { + Bundles []semverTemplateBundleEntry `json:"bundles,omitempty"` +} + +type semverTemplate struct { + Schema string `json:"schema"` + GenerateMajorChannels bool `json:"generateMajorChannels,omitempty"` + GenerateMinorChannels bool `json:"generateMinorChannels,omitempty"` + DefaultChannelTypePreference streamType `json:"defaultChannelTypePreference,omitempty"` + Candidate semverTemplateChannelBundles `json:"candidate,omitempty"` + Fast semverTemplateChannelBundles `json:"fast,omitempty"` + Stable semverTemplateChannelBundles `json:"stable,omitempty"` + + pkg string `json:"-"` // the derived package name + defaultChannel string `json:"-"` // detected "most stable" channel head +} + +// IO structs -- END + +const schema string = "olm.semver" + +// channel "archetypes", restricted in this iteration to just these +type channelArchetype string + +const ( + candidateChannelArchetype channelArchetype = "candidate" + fastChannelArchetype channelArchetype = "fast" + stableChannelArchetype channelArchetype = "stable" +) + +// mapping channel name --> stability, where higher values indicate greater stability +var channelPriorities = map[channelArchetype]int{candidateChannelArchetype: 0, fastChannelArchetype: 1, stableChannelArchetype: 2} + +// sorting capability for a slice according to the assigned channelPriorities +type byChannelPriority []channelArchetype + +func (b byChannelPriority) Len() int { return len(b) } +func (b byChannelPriority) Less(i, j int) bool { + return channelPriorities[b[i]] < channelPriorities[b[j]] +} +func (b byChannelPriority) Swap(i, j int) { b[i], b[j] = b[j], b[i] } + +type streamType string + +const defaultStreamType streamType = "" +const minorStreamType streamType = "minor" +const majorStreamType streamType = "major" + +// general preference for minor channels +var streamTypePriorities = map[streamType]int{minorStreamType: 2, majorStreamType: 1, defaultStreamType: 0} + +// map of archetypes --> bundles --> bundle-version from the input file +type bundleVersions map[channelArchetype]map[string]semver.Version // e.g. srcv["stable"]["example-operator.v1.0.0"] = 1.0.0 + +// the "high-water channel" struct functions as a freely-rising indicator of the "most stable" channel head, so we can use that +// later as the package's defaultChannel attribute +type highwaterChannel struct { + archetype channelArchetype + kind streamType + version semver.Version + name string +} diff --git a/appr-registry.Dockerfile b/appr-registry.Dockerfile deleted file mode 100644 index 468f93946..000000000 --- a/appr-registry.Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM golang:1.13-alpine as builder - -RUN apk update && apk add sqlite build-base git mercurial bash -WORKDIR /go/src/github.com/operator-framework/operator-registry - -COPY vendor vendor -COPY cmd cmd -COPY pkg pkg -COPY Makefile Makefile -COPY go.mod go.mod -RUN make static - -FROM golang:1.13-alpine as probe-builder - -RUN apk update && apk add build-base git -ENV ORG github.com/grpc-ecosystem -ENV PROJECT $ORG/grpc_health_probe -WORKDIR /go/src/$PROJECT - -COPY --from=builder /go/src/github.com/operator-framework/operator-registry/vendor/$ORG/grpc-health-probe . -COPY --from=builder /go/src/github.com/operator-framework/operator-registry/vendor . -RUN CGO_ENABLED=0 go install -a -tags netgo -ldflags "-w" - -FROM scratch -COPY --from=builder /go/src/github.com/operator-framework/operator-registry/bin/appregistry-server /bin/appregistry-server -COPY --from=probe-builder /go/bin/grpc-health-probe /bin/grpc_health_probe -EXPOSE 50051 -ENTRYPOINT ["/bin/appregistry-server"] diff --git a/bundles/apicurio-registry-operator.v1.0.0-v2.0.0.final/manifests/apicurio-registry-operator.clusterserviceversion.yaml b/bundles/apicurio-registry-operator.v1.0.0-v2.0.0.final/manifests/apicurio-registry-operator.clusterserviceversion.yaml new file mode 100644 index 000000000..fab60c275 --- /dev/null +++ b/bundles/apicurio-registry-operator.v1.0.0-v2.0.0.final/manifests/apicurio-registry-operator.clusterserviceversion.yaml @@ -0,0 +1,327 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "registry.apicur.io/v1", + "kind": "ApicurioRegistry", + "metadata": { + "name": "example-apicurioregistry-kafkasql" + }, + "spec": { + "configuration": { + "kafkasql": { + "bootstrapServers": "\u003cservice name\u003e.\u003cnamespace\u003e.svc:9092" + }, + "persistence": "kafkasql" + } + } + }, + { + "apiVersion": "registry.apicur.io/v1", + "kind": "ApicurioRegistry", + "metadata": { + "name": "example-apicurioregistry-mem" + }, + "spec": { + "configuration": { + "persistence": "mem" + } + } + }, + { + "apiVersion": "registry.apicur.io/v1", + "kind": "ApicurioRegistry", + "metadata": { + "name": "example-apicurioregistry-sql" + }, + "spec": { + "configuration": { + "persistence": "sql", + "sql": { + "dataSource": { + "password": "\u003cpassword\u003e", + "url": "jdbc:postgresql://\u003cservice name\u003e.\u003cnamespace\u003e.svc:5432/\u003cdatabase name\u003e", + "userName": "postgres" + } + } + } + } + } + ] + capabilities: Basic Install + categories: Streaming & Messaging + certified: "false" + containerImage: quay.io/apicurio/apicurio-registry-operator:1.0.0 + createdAt: 2021-05-19 + description: Deploy and manage Apicurio Registry on Kubernetes. + operators.operatorframework.io/builder: operator-sdk-v1.4.2 + operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 + repository: https://github.com/Apicurio/apicurio-registry-operator + support: Apicurio + name: apicurio-registry-operator.v1.0.0-v2.0.0.final + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: ApicurioRegistry represents an Apicurio Registry instance + displayName: Apicurio Registry + kind: ApicurioRegistry + name: apicurioregistries.registry.apicur.io + version: v1 + description: | + ## Apicurio Registry + + Apicurio Registry stores and retrieves API designs and event schemas, + and gives you control of their evolution. + + **Features** + - Supports: Apache Avro, AsyncAPI, GraphQL, JSON Schema, Kafka Connect Schema, OpenAPI, Protobuf + - Provides a REST API to manage the artifacts and artifact meta-data + - Includes Serializers and Deserializers for Kafka client integration + - Configurable rules to control schema validity and evolution (compatibility) + - Storage options: Kafka Streams, PostgreSQL, in-memory + - Compatible with Confluent and IBM APIs + - Runs on a lightweight Quarkus platform + - Includes Maven plugin to integrate with Maven based builds + + ## Apicurio Registry Operator + + Provides a quick and easy way to deploy and manage an Apicurio Registry on Kubernetes. + + **Features** + - Supports basic Install and configuration of the Registry + - Can optionally create an Ingress to access the API and UI on HTTP port 80 + - Manual horizontal scaling + - Easily perform a rolling upgrade of the Registry + + ## Prerequisites + + This operator does not deploy storage for the Registry. Therefore, some storage options require that the chosen persistence service is already set up. You can do this using an operator for the specified service, such as Strimzi for Kafka Streams. + displayName: Apicurio Registry Operator + icon: + - base64data: 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 + mediatype: image/jpeg + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - apps + resources: + - daemonsets + - deployments + - replicasets + - statefulsets + verbs: + - '*' + - apiGroups: + - apps.openshift.io + resources: + - deploymentconfigs + verbs: + - '*' + - apiGroups: + - config.openshift.io + resources: + - clusterversions + verbs: + - get + - apiGroups: + - "" + resources: + - configmaps + - endpoints + - persistentvolumeclaims + - pods + - secrets + - services + - services/finalizers + verbs: + - '*' + - apiGroups: + - events + resources: + - events + verbs: + - '*' + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - '*' + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - '*' + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - '*' + - apiGroups: + - registry.apicur.io + resources: + - apicurioregistries + verbs: + - '*' + - apiGroups: + - registry.apicur.io + resources: + - apicurioregistries/finalizers + verbs: + - update + - apiGroups: + - registry.apicur.io + resources: + - apicurioregistries/status + verbs: + - get + - patch + - update + - apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - '*' + serviceAccountName: apicurio-registry-operator + deployments: + - name: apicurio-registry-operator + spec: + replicas: 1 + selector: + matchLabels: + apicur.io/name: apicurio-registry-operator + apicur.io/type: operator + apicur.io/version: 1.0.0 + name: apicurio-registry-operator + strategy: {} + template: + metadata: + labels: + apicur.io/name: apicurio-registry-operator + apicur.io/type: operator + apicur.io/version: 1.0.0 + name: apicurio-registry-operator + spec: + containers: + - args: + - --leader-elect + command: + - /manager + env: + - name: REGISTRY_VERSION + value: 2.0.0.Final + - name: REGISTRY_IMAGE_MEM + value: quay.io/apicurio/apicurio-registry-mem:2.0.0.Final + - name: REGISTRY_IMAGE_KAFKASQL + value: quay.io/apicurio/apicurio-registry-kafkasql:2.0.0.Final + - name: REGISTRY_IMAGE_SQL + value: quay.io/apicurio/apicurio-registry-sql:2.0.0.Final + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: OPERATOR_NAME + value: apicurio-registry-operator + image: quay.io/apicurio/apicurio-registry-operator:1.0.0 + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: apicurio-registry-operator + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 100m + memory: 100Mi + requests: + cpu: 100m + memory: 50Mi + serviceAccountName: apicurio-registry-operator + terminationGracePeriodSeconds: 10 + permissions: + - rules: + - apiGroups: + - "" + - coordination.k8s.io + resources: + - configmaps + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: apicurio-registry-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - integration + - streaming + - messaging + - api + - schemas + - registry + - apicurio + - apicurio-registry + links: + - name: Website + url: https://www.apicur.io/ + - name: GitHub + url: https://github.com/Apicurio/apicurio-registry/ + - name: Issues + url: https://github.com/Apicurio/apicurio-registry/issues + - name: Twitter + url: https://twitter.com/Apicurio + maintainers: + - email: apicurio@lists.jboss.org + name: Apicurio + maturity: alpha + provider: + name: Apicurio + selector: {} + version: 1.0.0-v2.0.0.final diff --git a/bundles/apicurio-registry.v0.0.1/manifests/apicurio-registry-operator.v0.0.1.clusterserviceversion.yaml b/bundles/apicurio-registry.v0.0.1/manifests/apicurio-registry-operator.v0.0.1.clusterserviceversion.yaml new file mode 100644 index 000000000..9390151d7 --- /dev/null +++ b/bundles/apicurio-registry.v0.0.1/manifests/apicurio-registry-operator.v0.0.1.clusterserviceversion.yaml @@ -0,0 +1,277 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: apicurio-registry.v0.0.1 + namespace: placeholder + annotations: + # Setting olm.maxOpenShiftVersion automatically + # This property was added via an automatic process since it was possible to identify that this distribution uses API(s), + # which will be removed in the k8s version 1.22 and OpenShift version OCP 4.9. Then, it will prevent OCP users to + # upgrade their cluster to 4.9 before they have installed in their current clusters a version of your operator that + # is compatible with it. Please, ensure that your project is no longer using these API(s) and that you start to + # distribute solutions which is compatible with Openshift 4.9. + # For further information, check the README of this repository. + olm.properties: '[{"type": "olm.maxOpenShiftVersion", "value": "4.8"}]' + alm-examples: >- + [{"apiVersion":"apicur.io/v1alpha1","kind":"ApicurioRegistry","metadata":{"name":"example-apicurioregistry"},"spec":{"image":{"registry":"docker.io/apicurio","version":"latest-release"},"configuration":{"persistence":"mem"},"deployment":{"route":"registry.example.com"}}}] + categories: ' Streaming & Messaging' + certified: 'false' + createdAt: '2020-05-27' + description: Deploy and manage Apicurio Registry on Kubernetes. + containerImage: 'apicurio/apicurio-registry-operator:0.0.1' + support: 'Apicurio Project' + capabilities: Basic Install + repository: 'https://github.com/Apicurio/apicurio-registry-operator' +spec: + displayName: Apicurio Registry Operator + description: > + ## Apicurio Registry + + + Apicurio Registry stores and retrieves API designs and event schemas, and + gives you control of their evolution. + + + **Features** + + - Supports: Apache Avro, AsyncAPI, GraphQL, JSON Schema, Kafka Connect + Schema, OpenAPI, Protobuf + + - Provides a REST API to manage the artifacts and artifact meta-data + + - Includes Serializers and Deserializers for Kafka client integration + + - Configurable rules to control schema validity and evolution + (compatibility) + + - Storage options: Kafka Streams, Kafka, PostgreSQL, in-memory + + - Compatible with Confluent and IBM APIs + + - Runs on a lightweight Quarkus platform + + - Includes Maven plugin to integrate with Maven based builds + + ## Apicurio Registry Operator + + + Provides a quick and easy way to deploy and manage an Apicurio Registry on + Kubernetes. + + + **Features** + + - Supports basic Install and configuration of the Registry + + - Can optionally create an Ingress to access the API and UI on HTTP port 80 + + - Manual horizontal scaling + + - Easily perform a rolling upgrade of the Registry + + ## Prerequisites + + This operator does not deploy storage for the Registry. Therefore, some storage options require that the chosen persistence service is already set up. You can do this using an operator for the specified service, such as Strimzi for Kafka Streams. + maturity: alpha + version: 0.0.1 + skips: [] + minKubeVersion: '' + keywords: [] + maintainers: + - name: Apicurio + email: 'apicurio@lists.jboss.org' + provider: + name: Apicurio + labels: {} + selector: + matchLabels: {} + links: + - name: Website + url: 'https://www.apicur.io/' + - name: GitHub + url: 'https://github.com/Apicurio/apicurio-registry/' + - name: Issues + url: 'https://github.com/Apicurio/apicurio-registry/issues' + - name: Twitter + url: 'https://twitter.com/Apicurio' + icon: + - base64data: >- + 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 + mediatype: image/jpeg + customresourcedefinitions: + owned: + - name: apicurioregistries.apicur.io + displayName: ApicurioRegistry + kind: ApicurioRegistry + version: v1alpha1 + description: Apicurio Registry + resources: + - version: v1 + kind: Deployment + - version: v1 + kind: Service + - version: v1 + kind: ReplicaSet + - version: v1 + kind: Pod + - version: v1 + kind: Secret + - version: v1 + kind: ConfigMap + specDescriptors: + - path: configuration + description: Configuration + displayName: Configuration + x-descriptors: [] + - path: deployment + description: Deployment + displayName: Deployment + x-descriptors: [] + - path: image + description: Image + displayName: Image + x-descriptors: [] + statusDescriptors: + - path: deploymentName + description: Deployment Name + displayName: Deployment Name + x-descriptors: [] + - path: image + description: Image + displayName: Image + x-descriptors: [] + - path: ingressName + description: Ingress Name + displayName: Ingress Name + x-descriptors: [] + - path: replicaCount + description: Replica Count + displayName: Replica Count + x-descriptors: [] + - path: route + description: Route + displayName: Route + x-descriptors: [] + - path: serviceName + description: Service Name + displayName: Service Name + x-descriptors: [] + required: [] + install: + strategy: deployment + spec: + permissions: + - serviceAccountName: apicurio-registry + rules: + - apiGroups: + - route.openshift.io + - apps.openshift.io + resources: + - routes/custom-host + - deploymentconfigs + verbs: + - '*' + - apiGroups: + - '' + - extensions + - route.openshift.io + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + - ingresses + - routes/custom-host + verbs: + - '*' + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create + - apiGroups: + - apps + resourceNames: + - apicurio-registry + resources: + - deployments/finalizers + verbs: + - update + - apiGroups: + - '' + resources: + - pods + verbs: + - get + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - apiGroups: + - apicur.io + resources: + - '*' + verbs: + - '*' + clusterPermissions: + - serviceAccountName: apicurio-registry + rules: + - apiGroups: + - config.openshift.io + resources: + - clusterversions + verbs: + - get + deployments: + - name: apicurio-registry + spec: + replicas: 1 + selector: + matchLabels: + name: apicurio-registry + template: + metadata: + labels: + name: apicurio-registry + spec: + serviceAccountName: apicurio-registry + containers: + - name: apicurio-registry + image: 'apicurio/apicurio-registry-operator:0.0.1' + imagePullPolicy: Always + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: apicurio-registry + installModes: + - type: OwnNamespace + supported: true + - type: SingleNamespace + supported: true + - type: MultiNamespace + supported: false + - type: AllNamespaces + supported: false diff --git a/bundles/apicurio-registry.v0.0.3-v1.2.3.final/manifests/apicurio-registry.v0.0.3-v1.2.3.final.clusterserviceversion.yaml b/bundles/apicurio-registry.v0.0.3-v1.2.3.final/manifests/apicurio-registry.v0.0.3-v1.2.3.final.clusterserviceversion.yaml new file mode 100644 index 000000000..5fa602891 --- /dev/null +++ b/bundles/apicurio-registry.v0.0.3-v1.2.3.final/manifests/apicurio-registry.v0.0.3-v1.2.3.final.clusterserviceversion.yaml @@ -0,0 +1,266 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + # Setting olm.maxOpenShiftVersion automatically + # This property was added via an automatic process since it was possible to identify that this distribution uses API(s), + # which will be removed in the k8s version 1.22 and OpenShift version OCP 4.9. Then, it will prevent OCP users to + # upgrade their cluster to 4.9 before they have installed in their current clusters a version of your operator that + # is compatible with it. Please, ensure that your project is no longer using these API(s) and that you start to + # distribute solutions which is compatible with Openshift 4.9. + # For further information, check the README of this repository. + olm.properties: '[{"type": "olm.maxOpenShiftVersion", "value": "4.8"}]' + alm-examples: |- + [ + { + "apiVersion": "apicur.io/v1alpha1", + "kind": "ApicurioRegistry", + "metadata": { + "name": "example-apicurioregistry" + } + } + ] + capabilities: Basic Install + categories: Streaming & Messaging + certified: 'false' + containerImage: docker.io/apicurio/apicurio-registry-operator:0.0.3 + createdAt: 2020-07-08 + description: Deploy and manage Apicurio Registry on Kubernetes. + repository: https://github.com/Apicurio/apicurio-registry-operator + support: Apicurio + name: apicurio-registry.v0.0.3-v1.2.3.final + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: ApicurioRegistry is the Schema for the apicurioregistries API + kind: ApicurioRegistry + name: apicurioregistries.apicur.io + version: v1alpha1 + description: | + ## Apicurio Registry + + Apicurio Registry stores and retrieves API designs and event schemas, + and gives you control of their evolution. + + **Features** + - Supports: Apache Avro, AsyncAPI, GraphQL, JSON Schema, Kafka Connect Schema, OpenAPI, Protobuf + - Provides a REST API to manage the artifacts and artifact meta-data + - Includes Serializers and Deserializers for Kafka client integration + - Configurable rules to control schema validity and evolution (compatibility) + - Storage options: Kafka Streams, Kafka, PostgreSQL, in-memory + - Compatible with Confluent and IBM APIs + - Runs on a lightweight Quarkus platform + - Includes Maven plugin to integrate with Maven based builds + + ## Apicurio Registry Operator + + Provides a quick and easy way to deploy and manage an Apicurio Registry on Kubernetes. + + **Features** + - Supports basic Install and configuration of the Registry + - Can optionally create an Ingress to access the API and UI on HTTP port 80 + - Manual horizontal scaling + - Easily perform a rolling upgrade of the Registry + + ## Prerequisites + + This operator does not deploy storage for the Registry. Therefore, some storage options require that the chosen persistence service is already set up. You can do this using an operator for the specified service, such as Strimzi for Kafka Streams. + displayName: Apicurio Registry Operator + icon: + - base64data: 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 + mediatype: image/jpeg + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - config.openshift.io + resources: + - clusterversions + verbs: + - get + - apiGroups: + - apicur.io + resources: + - apicurioregistries + verbs: + - '*' + serviceAccountName: apicurio-registry-operator + deployments: + - name: apicurio-registry-operator + spec: + replicas: 1 + selector: + matchLabels: + name: apicurio-registry-operator + strategy: {} + template: + metadata: + labels: + name: apicurio-registry-operator + spec: + containers: + - env: + - name: REGISTRY_IMAGE_MEM + value: docker.io/apicurio/apicurio-registry-mem@sha256:e4712e66edfc0a217531c282b1e2513172c993b5eb37f5c1024b2c14af6d7874 + - name: REGISTRY_IMAGE_KAFKA + value: docker.io/apicurio/apicurio-registry-kafka@sha256:d4748be356fe135be9cd58e679182d3e2f9023ab7421cf3923fb54cd8666f2c9 + - name: REGISTRY_IMAGE_STREAMS + value: docker.io/apicurio/apicurio-registry-streams@sha256:ed272fb0c50f828e67d9c9ff885786043de356da389b169cc790c6169f084174 + - name: REGISTRY_IMAGE_JPA + value: docker.io/apicurio/apicurio-registry-jpa@sha256:f32d41977224d99eea6769b4b4ce3de3c2690be4af107f1eae6d42f8ae536a94 + - name: REGISTRY_IMAGE_INFINISPAN + value: docker.io/apicurio/apicurio-registry-infinispan@sha256:7a7936fde7058c360e98406019f1291e57b1895884f5563e0e71cc5e3c6a04fb + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: apicurio-registry-operator + image: docker.io/apicurio/apicurio-registry-operator@sha256:7d5164d09818a9605fbf8d1f8695206cf929bf17b267fc32d0ee3ca9d6ab5d4b + imagePullPolicy: Always + name: apicurio-registry-operator + resources: + limits: + cpu: 4m + memory: 64Mi + requests: + cpu: 2m + memory: 32Mi + serviceAccountName: apicurio-registry-operator + permissions: + - rules: + - apiGroups: + - route.openshift.io + - apps.openshift.io + resources: + - routes + - routes/custom-host + - deploymentconfigs + verbs: + - '*' + - apiGroups: + - "" + - extensions + - route.openshift.io + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + - ingresses + - routes/custom-host + verbs: + - '*' + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - '*' + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create + - apiGroups: + - apps + resourceNames: + - apicurio-registry-operator + resources: + - deployments/finalizers + verbs: + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - apiGroups: + - apicur.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - "" + resources: + - services/finalizers + verbs: + - update + serviceAccountName: apicurio-registry-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: false + type: AllNamespaces + keywords: + - integration + - streaming + - messaging + - api + - schemas + - registry + - apicurio + - apicurio-registry + links: + - name: Website + url: https://www.apicur.io/ + - name: GitHub + url: https://github.com/Apicurio/apicurio-registry/ + - name: Issues + url: https://github.com/Apicurio/apicurio-registry/issues + - name: Twitter + url: https://twitter.com/Apicurio + maintainers: + - email: apicurio@lists.jboss.org + name: Apicurio + maturity: alpha + provider: + name: Apicurio + relatedImages: + - name: apicurio-registry-mem + image: docker.io/apicurio/apicurio-registry-mem@sha256:e4712e66edfc0a217531c282b1e2513172c993b5eb37f5c1024b2c14af6d7874 + - name: apicurio-registry-kafka + image: docker.io/apicurio/apicurio-registry-kafka@sha256:d4748be356fe135be9cd58e679182d3e2f9023ab7421cf3923fb54cd8666f2c9 + - name: apicurio-registry-streams + image: docker.io/apicurio/apicurio-registry-streams@sha256:ed272fb0c50f828e67d9c9ff885786043de356da389b169cc790c6169f084174 + - name: apicurio-registry-jpa + image: docker.io/apicurio/apicurio-registry-jpa@sha256:f32d41977224d99eea6769b4b4ce3de3c2690be4af107f1eae6d42f8ae536a94 + - name: apicurio-registry-infinispan + image: docker.io/apicurio/apicurio-registry-infinispan@sha256:7a7936fde7058c360e98406019f1291e57b1895884f5563e0e71cc5e3c6a04fb + replaces: apicurio-registry.v0.0.1 + selector: {} + version: 0.0.3-v1.2.3.final diff --git a/bundles/apicurio-registry.v0.0.4-v1.3.2.final/manifests/apicurio-registry.v0.0.4-v1.3.2.final.clusterserviceversion.yaml b/bundles/apicurio-registry.v0.0.4-v1.3.2.final/manifests/apicurio-registry.v0.0.4-v1.3.2.final.clusterserviceversion.yaml new file mode 100644 index 000000000..eec0686f1 --- /dev/null +++ b/bundles/apicurio-registry.v0.0.4-v1.3.2.final/manifests/apicurio-registry.v0.0.4-v1.3.2.final.clusterserviceversion.yaml @@ -0,0 +1,391 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + # Setting olm.maxOpenShiftVersion automatically + # This property was added via an automatic process since it was possible to identify that this distribution uses API(s), + # which will be removed in the k8s version 1.22 and OpenShift version OCP 4.9. Then, it will prevent OCP users to + # upgrade their cluster to 4.9 before they have installed in their current clusters a version of your operator that + # is compatible with it. Please, ensure that your project is no longer using these API(s) and that you start to + # distribute solutions which is compatible with Openshift 4.9. + # For further information, check the README of this repository. + olm.properties: '[{"type": "olm.maxOpenShiftVersion", "value": "4.8"}]' + alm-examples: |- + [ + { + "apiVersion": "apicur.io/v1alpha1", + "kind": "ApicurioRegistry", + "metadata": { + "name": "example-apicurioregistry" + } + } + ] + capabilities: Basic Install + categories: Streaming & Messaging + certified: "false" + containerImage: docker.io/apicurio/apicurio-registry-operator:0.0.4 + createdAt: 2020-11-18 + description: Deploy and manage Apicurio Registry on Kubernetes. + repository: https://github.com/Apicurio/apicurio-registry-operator + support: Apicurio + name: apicurio-registry.v0.0.4-v1.3.2.final + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: ApicurioRegistry is the Schema for the apicurioregistries API + kind: ApicurioRegistry + name: apicurioregistries.apicur.io + version: v1alpha1 + specDescriptors: + - description: The DataSource user name + displayName: User Name + path: configuration.dataSource.userName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:dataSource + - urn:alm:descriptor:com.tectonic.ui:text + - description: The DataSource Password + displayName: Password + path: configuration.dataSource.password + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:dataSource + - urn:alm:descriptor:com.tectonic.ui:password + - description: The DataSource URL + displayName: URL + path: configuration.dataSource.url + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:dataSource + - urn:alm:descriptor:com.tectonic.ui:text + - description: The Infinispan Cluster Name + displayName: Cluster Name + path: configuration.infinispan.clusterName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:infinispan + - urn:alm:descriptor:com.tectonic.ui:text + - description: The kafka Bootstrap Servers + displayName: Bootstrap Servers + path: configuration.kafka.bootstrapServers + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:kafka + - urn:alm:descriptor:com.tectonic.ui:text + - description: Log Level + displayName: Log Level + path: configuration.logLevel + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:logLevel + - urn:alm:descriptor:com.tectonic.ui:text + - description: Select the Persistence Type + displayName: Persistence Type + path: configuration.persistence + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:persistence + - urn:alm:descriptor:com.tectonic.ui:select + - description: Application Id + displayName: Application Id + path: configuration.streams.applicationId + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:streams + - urn:alm:descriptor:com.tectonic.ui:text + - description: Application Server Port + displayName: Application Server Port + path: configuration.streams.applicationServerPort + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:streams + - urn:alm:descriptor:com.tectonic.ui:text + - description: Bootstrap Servers + displayName: Bootstrap Servers + path: configuration.streams.bootstrapServers + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:streams + - urn:alm:descriptor:com.tectonic.ui:text + - description: Mechanism + displayName: Mechanism + path: configuration.streams.security.scram.mechanism + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:scram + - urn:alm:descriptor:com.tectonic.ui:text + - description: Password Secret Name + displayName: Password Secret Name + path: configuration.streams.security.scram.passwordSecretName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:scram + - urn:alm:descriptor:com.tectonic.ui:text + - description: Truststore Secret Name + displayName: Truststore Secret Name + path: configuration.streams.security.scram.truststoreSecretName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:scram + - urn:alm:descriptor:com.tectonic.ui:text + - description: User + displayName: User + path: configuration.streams.security.scram.user + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:scram + - urn:alm:descriptor:com.tectonic.ui:text + - description: Keystore Secret Name + displayName: Keystore Secret Name + path: configuration.streams.security.tls.keystoreSecretName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:tls + - urn:alm:descriptor:com.tectonic.ui:text + - description: Truststore Secret Name + displayName: Truststore Secret Name + path: configuration.streams.security.tls.truststoreSecretName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:tls + - urn:alm:descriptor:com.tectonic.ui:text + - description: Read Only + displayName: Read Only + path: configuration.ui.readOnly + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:ui + - urn:alm:descriptor:com.tectonic.ui:booleanSwitch + - description: Override the image name according to selected Persistence Type for example, MEM="docker.io/apicurio/apicurio-registry-mem:1.3.2.Final" KAFKA="docker.io/apicurio/apicurio-registry-kafka:1.3.2.Final" STREAMS="docker.io/apicurio/apicurio-registry-streams:1.3.2.Final" JPA="docker.io/apicurio/apicurio-registry-jpa:1.3.2.Final" INFINISPAN="docker.io/apicurio/apicurio-registry-infinispan:1.3.2.Final" + displayName: Image Name + path: image.name + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:image + - urn:alm:descriptor:com.tectonic.ui:text + - description: The number of replicas + displayName: Replicas + path: deployment.replicas + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:fieldGroup:deployment + - urn:alm:descriptor:com.tectonic.ui:podCount + description: | + ## Apicurio Registry + + Apicurio Registry stores and retrieves API designs and event schemas, + and gives you control of their evolution. + + **Features** + - Supports: Apache Avro, AsyncAPI, GraphQL, JSON Schema, Kafka Connect Schema, OpenAPI, Protobuf + - Provides a REST API to manage the artifacts and artifact meta-data + - Includes Serializers and Deserializers for Kafka client integration + - Configurable rules to control schema validity and evolution (compatibility) + - Storage options: Kafka Streams, Kafka, PostgreSQL, in-memory + - Compatible with Confluent and IBM APIs + - Runs on a lightweight Quarkus platform + - Includes Maven plugin to integrate with Maven based builds + + ## Apicurio Registry Operator + + Provides a quick and easy way to deploy and manage an Apicurio Registry on Kubernetes. + + **Features** + - Supports basic Install and configuration of the Registry + - Can optionally create an Ingress to access the API and UI on HTTP port 80 + - Manual horizontal scaling + - Easily perform a rolling upgrade of the Registry + + ## Prerequisites + + This operator does not deploy storage for the Registry. Therefore, some storage options require that the chosen persistence service is already set up. You can do this using an operator for the specified service, such as Strimzi for Kafka Streams. + displayName: Apicurio Registry Operator + icon: + - base64data: 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 + mediatype: image/jpeg + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - config.openshift.io + resources: + - clusterversions + verbs: + - get + - apiGroups: + - apicur.io + resources: + - apicurioregistries + verbs: + - '*' + serviceAccountName: apicurio-registry-operator + deployments: + - name: apicurio-registry-operator + spec: + replicas: 1 + selector: + matchLabels: + name: apicurio-registry-operator + strategy: {} + template: + metadata: + labels: + apicur.io/name: apicurio-registry-operator + apicur.io/type: operator + apicur.io/version: 0.0.4 + name: apicurio-registry-operator + spec: + containers: + - env: + - name: REGISTRY_VERSION + value: 1.3.2.Final + - name: REGISTRY_IMAGE_MEM + value: docker.io/apicurio/apicurio-registry-mem@sha256:9e3e35e16a72c6c065b4be6c1fabcb2e9f7ed73b36600e05b1e46b4cc394413f # 1.3.2.Final + - name: REGISTRY_IMAGE_KAFKA + value: docker.io/apicurio/apicurio-registry-kafka@sha256:cdac38135c67f3da808e55b16beaa4fc3cc67b846af1e64f491417d4107d60aa # 1.3.2.Final + - name: REGISTRY_IMAGE_STREAMS + value: docker.io/apicurio/apicurio-registry-streams@sha256:d3bfb0d13498dedd563d7b45dfa2461e560bf0fbf08ff3767254bb8a198f4845 # 1.3.2.Final + - name: REGISTRY_IMAGE_JPA + value: docker.io/apicurio/apicurio-registry-jpa@sha256:44eeddd3562ca3ac3f5fb440e5f68880ab9b4d6caa0b34541a9178c4a039b1f4 # 1.3.2.Final + - name: REGISTRY_IMAGE_INFINISPAN + value: docker.io/apicurio/apicurio-registry-infinispan@sha256:4dfe0cba302f8243c5c2312df845eed6690381e8d44072c5f5ab96241b5d2dde # 1.3.2.Final + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.annotations['olm.targetNamespaces'] + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: OPERATOR_NAME + value: apicurio-registry-operator + image: docker.io/apicurio/apicurio-registry-operator@sha256:d9477c73b855f9821f4a8aca491407e065d34b5bdc795e3ad49a0537fd6ceeaa # 0.0.4 + imagePullPolicy: Always + name: apicurio-registry-operator + resources: + limits: + cpu: 4m + memory: 64Mi + requests: + cpu: 2m + memory: 32Mi + serviceAccountName: apicurio-registry-operator + permissions: + - rules: + - apiGroups: + - route.openshift.io + - apps.openshift.io + resources: + - routes + - routes/custom-host + - deploymentconfigs + verbs: + - '*' + - apiGroups: + - "" + - extensions + - route.openshift.io + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + - ingresses + - routes/custom-host + verbs: + - '*' + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - '*' + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - '*' + - apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - '*' + - apiGroups: + - apps + resourceNames: + - apicurio-registry-operator + resources: + - deployments/finalizers + verbs: + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - apiGroups: + - apicur.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - "" + resources: + - services/finalizers + verbs: + - update + serviceAccountName: apicurio-registry-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: false + type: AllNamespaces + keywords: + - integration + - streaming + - messaging + - api + - schemas + - registry + - apicurio + - apicurio-registry + links: + - name: Website + url: https://www.apicur.io/ + - name: GitHub + url: https://github.com/Apicurio/apicurio-registry/ + - name: Issues + url: https://github.com/Apicurio/apicurio-registry/issues + - name: Twitter + url: https://twitter.com/Apicurio + maintainers: + - email: apicurio@lists.jboss.org + name: Apicurio + maturity: alpha + provider: + name: Apicurio + replaces: apicurio-registry.v0.0.3-v1.2.3.final + selector: {} + version: 0.0.4-v1.3.2.final + relatedImages: + - name: apicurio-registry-operator + image: docker.io/apicurio/apicurio-registry-operator@sha256:d9477c73b855f9821f4a8aca491407e065d34b5bdc795e3ad49a0537fd6ceeaa + - name: apicurio-registry-mem + image: docker.io/apicurio/apicurio-registry-mem@sha256:9e3e35e16a72c6c065b4be6c1fabcb2e9f7ed73b36600e05b1e46b4cc394413f + - name: apicurio-registry-kafka + image: docker.io/apicurio/apicurio-registry-kafka@sha256:cdac38135c67f3da808e55b16beaa4fc3cc67b846af1e64f491417d4107d60aa + - name: apicurio-registry-streams + image: docker.io/apicurio/apicurio-registry-streams@sha256:d3bfb0d13498dedd563d7b45dfa2461e560bf0fbf08ff3767254bb8a198f4845 + - name: apicurio-registry-jpa + image: docker.io/apicurio/apicurio-registry-jpa@sha256:44eeddd3562ca3ac3f5fb440e5f68880ab9b4d6caa0b34541a9178c4a039b1f4 + - name: apicurio-registry-infinispan + image: docker.io/apicurio/apicurio-registry-infinispan@sha256:4dfe0cba302f8243c5c2312df845eed6690381e8d44072c5f5ab96241b5d2dde diff --git a/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml b/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml index 69266c011..6eba3fd65 100644 --- a/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml +++ b/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml @@ -17,7 +17,7 @@ spec: ### Reading and writing to etcd - Communicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service. + Communicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service. [Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html) diff --git a/bundles/etcd.0.9.0/metadata/annotations.yaml b/bundles/etcd.0.9.0/metadata/annotations.yaml index d347fc860..4fde28c28 100644 --- a/bundles/etcd.0.9.0/metadata/annotations.yaml +++ b/bundles/etcd.0.9.0/metadata/annotations.yaml @@ -1,4 +1,5 @@ annotations: operators.operatorframework.io.bundle.package.v1: "etcd" - operators.operatorframework.io.bundle.channels.v1: "alpha,stable" - operators.operatorframework.io.bundle.channel.default.v1: "stable" \ No newline at end of file + operators.operatorframework.io.bundle.channels.v1: "alpha,stable,beta" + operators.operatorframework.io.bundle.channel.default.v1: "stable" + \ No newline at end of file diff --git a/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml b/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml index 137d88095..2d7909001 100644 --- a/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml +++ b/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml @@ -17,7 +17,7 @@ spec: ### Reading and writing to etcd - Communicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service. + Communicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service. [Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html) diff --git a/bundles/etcd.0.9.2/metadata/dependencies.yaml b/bundles/etcd.0.9.2/metadata/dependencies.yaml index ed19d0447..41903694a 100644 --- a/bundles/etcd.0.9.2/metadata/dependencies.yaml +++ b/bundles/etcd.0.9.2/metadata/dependencies.yaml @@ -1,5 +1,11 @@ dependencies: - - type: olm.gvk +- type: olm.gvk + value: group: testapi.coreos.com kind: testapi version: v1 +- type: olm.constraint + value: + failureMessage: 'require to have "certified"' + cel: + rule: 'properties.exists(p, p.type == "certified")' diff --git a/bundles/prometheus.0.14.0-beta/manifests/prometheusoperator.0.14.0.clusterserviceversion.yaml b/bundles/prometheus.0.14.0-beta/manifests/prometheusoperator.0.14.0.clusterserviceversion.yaml index 90feaf2e5..467c42a6f 100644 --- a/bundles/prometheus.0.14.0-beta/manifests/prometheusoperator.0.14.0.clusterserviceversion.yaml +++ b/bundles/prometheus.0.14.0-beta/manifests/prometheusoperator.0.14.0.clusterserviceversion.yaml @@ -154,7 +154,7 @@ spec: cpu: 100m memory: 50Mi maturity: alpha - version: 0.14.0 + version: 0.14.0-beta customresourcedefinitions: owned: - name: prometheuses.monitoring.coreos.com diff --git a/bundles/prometheus.0.14.0.substitutesfor/manifests/alertmanager.crd.yaml b/bundles/prometheus.0.14.0.substitutesfor/manifests/alertmanager.crd.yaml new file mode 100644 index 000000000..ce56f4bb6 --- /dev/null +++ b/bundles/prometheus.0.14.0.substitutesfor/manifests/alertmanager.crd.yaml @@ -0,0 +1,2398 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: alertmanagers.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + kind: Alertmanager + plural: alertmanagers + scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + description: 'Specification of the desired behavior of the Alertmanager + cluster. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-statu