diff --git a/.goreleaser.yml b/.goreleaser.yml index b09c07af..e0dfe48e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -9,6 +9,8 @@ builds: asmflags: "{{ .Env.GO_BUILD_ASMFLAGS }}" gcflags: "{{ .Env.GO_BUILD_GCFLAGS }}" ldflags: "{{ .Env.GO_BUILD_LDFLAGS }}" + tags: + - "{{ .Env.GO_BUILD_TAGS }}" mod_timestamp: "{{ .CommitTimestamp }}" goos: - linux diff --git a/Makefile b/Makefile index 43da8b35..c828add2 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,9 @@ ifeq ($(shell [[ $$HOME == "" || $$HOME == "/" ]] && [[ $$XDG_DATA_HOME == "" ]] SETUP_ENVTEST_BIN_DIR_OVERRIDE += --bin-dir /tmp/envtest-binaries endif +# For standard development and release flows, we use the config/overlays/cert-manager overlay. +KUSTOMIZE_OVERLAY := config/overlays/cert-manager + # bingo manages consistent tooling versions for things like kind, kustomize, etc. include .bingo/Variables.mk @@ -75,7 +78,7 @@ fmt: ## Run go fmt against code. .PHONY: vet vet: ## Run go vet against code. - go vet ./... + go vet -tags '$(GO_BUILD_TAGS)' ./... .PHONY: bingo-upgrade bingo-upgrade: $(BINGO) #EXHELP Upgrade tools @@ -85,8 +88,13 @@ bingo-upgrade: $(BINGO) #EXHELP Upgrade tools done .PHONY: test-unit +UNIT_TEST_DIRS := $(shell go list ./... | grep -v /test/e2e | grep -v /test/upgrade) test-unit: generate fmt vet $(SETUP_ENVTEST) ## Run tests. - eval $$($(SETUP_ENVTEST) use -p env $(ENVTEST_SERVER_VERSION) $(SETUP_ENVTEST_BIN_DIR_OVERRIDE)) && go test $(shell go list ./... | grep -v /test/e2e | grep -v /test/upgrade) -coverprofile cover.out + eval $$($(SETUP_ENVTEST) use -p env $(ENVTEST_SERVER_VERSION) $(SETUP_ENVTEST_BIN_DIR_OVERRIDE)) && \ + go test \ + -tags '$(GO_BUILD_TAGS)' \ + -coverprofile cover.out \ + $(UNIT_TEST_DIRS) FOCUS := $(if $(TEST),-v -focus "$(TEST)") ifeq ($(origin E2E_FLAGS), undefined) @@ -95,11 +103,14 @@ endif test-e2e: $(GINKGO) ## Run the e2e tests $(GINKGO) $(E2E_FLAGS) -trace -vv $(FOCUS) test/e2e -e2e: KIND_CLUSTER_NAME=catalogd-e2e +e2e: KIND_CLUSTER_NAME := catalogd-e2e +e2e: ISSUER_KIND := Issuer +e2e: ISSUER_NAME := selfsigned-issuer +e2e: KUSTOMIZE_OVERLAY := config/overlays/e2e e2e: run image-registry test-e2e kind-cluster-cleanup ## Run e2e test suite on local kind cluster image-registry: ## Setup in-cluster image registry - ./test/tools/imageregistry/registry.sh + ./test/tools/imageregistry/registry.sh $(ISSUER_KIND) $(ISSUER_NAME) .PHONY: tidy tidy: ## Update dependencies @@ -111,13 +122,15 @@ verify: tidy fmt vet generate ## Verify the current code generation and lint .PHONY: lint lint: $(GOLANGCI_LINT) ## Run golangci linter. - $(GOLANGCI_LINT) run $(GOLANGCI_LINT_ARGS) + $(GOLANGCI_LINT) run --build-tags $(GO_BUILD_TAGS) $(GOLANGCI_LINT_ARGS) ## image-registry target has to come after run-latest-release, ## because the image-registry depends on the olm-ca issuer. .PHONY: test-upgrade-e2e test-upgrade-e2e: export TEST_CLUSTER_CATALOG_NAME := test-catalog test-upgrade-e2e: export TEST_CLUSTER_CATALOG_IMAGE := docker-registry.catalogd-e2e.svc:5000/test-catalog:e2e +test-upgrade-e2e: ISSUER_KIND=ClusterIssuer +test-upgrade-e2e: ISSUER_NAME=olmv1-ca test-upgrade-e2e: kind-cluster cert-manager build-container kind-load run-latest-release image-registry pre-upgrade-setup only-deploy-manifest wait post-upgrade-checks kind-cluster-cleanup ## Run upgrade e2e tests on a local kind cluster pre-upgrade-setup: @@ -157,8 +170,9 @@ export GO_BUILD_LDFLAGS := -s -w \ -X "$(VERSION_PKG).gitTreeState=$(GIT_TREE_STATE)" \ -X "$(VERSION_PKG).commitDate=$(GIT_COMMIT_DATE)" export GO_BUILD_GCFLAGS := all=-trimpath=${PWD} +export GO_BUILD_TAGS := containers_image_openpgp -BUILDCMD = go build -ldflags '$(GO_BUILD_LDFLAGS)' -gcflags '$(GO_BUILD_GCFLAGS)' -asmflags '$(GO_BUILD_ASMFLAGS)' -o $(BUILDBIN)/$(notdir $@) ./cmd/$(notdir $@) +BUILDCMD = go build -tags '$(GO_BUILD_TAGS)' -ldflags '$(GO_BUILD_LDFLAGS)' -gcflags '$(GO_BUILD_GCFLAGS)' -asmflags '$(GO_BUILD_ASMFLAGS)' -o $(BUILDBIN)/$(notdir $@) ./cmd/$(notdir $@) .PHONY: build-deps build-deps: generate fmt vet @@ -209,13 +223,13 @@ deploy: export MANIFEST="./catalogd.yaml" deploy: export DEFAULT_CATALOGS="./config/base/default/clustercatalogs/default-catalogs.yaml" deploy: $(KUSTOMIZE) ## Deploy Catalogd to the K8s cluster specified in ~/.kube/config with cert-manager and default clustercatalogs cd config/base/manager && $(KUSTOMIZE) edit set image controller=$(IMAGE) && cd ../../.. - $(KUSTOMIZE) build config/overlays/cert-manager | sed "s/cert-git-version/cert-$(GIT_VERSION)/g" > catalogd.yaml + $(KUSTOMIZE) build $(KUSTOMIZE_OVERLAY) | sed "s/cert-git-version/cert-$(GIT_VERSION)/g" > catalogd.yaml envsubst '$$CERT_MGR_VERSION,$$MANIFEST,$$DEFAULT_CATALOGS' < scripts/install.tpl.sh | bash -s .PHONY: only-deploy-manifest only-deploy-manifest: $(KUSTOMIZE) ## Deploy just the Catalogd manifest--used in e2e testing where cert-manager is installed in a separate step cd config/base/manager && $(KUSTOMIZE) edit set image controller=$(IMAGE) - $(KUSTOMIZE) build config/overlays/cert-manager | kubectl apply -f - + $(KUSTOMIZE) build $(KUSTOMIZE_OVERLAY) | kubectl apply -f - wait: kubectl wait --for=condition=Available --namespace=$(CATALOGD_NAMESPACE) deployment/catalogd-controller-manager --timeout=60s @@ -244,7 +258,7 @@ release: $(GORELEASER) ## Runs goreleaser for catalogd. By default, this will ru quickstart: export MANIFEST := https://github.com/operator-framework/catalogd/releases/download/$(VERSION)/catalogd.yaml quickstart: export DEFAULT_CATALOGS := https://github.com/operator-framework/catalogd/releases/download/$(VERSION)/default-catalogs.yaml quickstart: $(KUSTOMIZE) generate ## Generate the installation release manifests and scripts - $(KUSTOMIZE) build config/overlays/cert-manager | sed "s/:devel/:$(GIT_VERSION)/g" | sed "s/cert-git-version/cert-$(GIT_VERSION)/g" > catalogd.yaml + $(KUSTOMIZE) build $(KUSTOMIZE_OVERLAY) | sed "s/:devel/:$(GIT_VERSION)/g" | sed "s/cert-git-version/cert-$(GIT_VERSION)/g" > catalogd.yaml envsubst '$$CERT_MGR_VERSION,$$MANIFEST,$$DEFAULT_CATALOGS' < scripts/install.tpl.sh > install.sh .PHONY: demo-update diff --git a/Tiltfile b/Tiltfile index b34713f2..e937a3e9 100644 --- a/Tiltfile +++ b/Tiltfile @@ -12,4 +12,4 @@ repo = { 'starting_debug_port': 20000, } -deploy_repo('catalogd', repo) +deploy_repo('catalogd', repo, '-tags containers_image_openpgp') diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 40c4069c..b96bbce0 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -26,6 +26,7 @@ import ( "path/filepath" "time" + "github.com/containers/image/v5/types" "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -44,7 +45,6 @@ import ( corecontrollers "github.com/operator-framework/catalogd/internal/controllers/core" "github.com/operator-framework/catalogd/internal/features" "github.com/operator-framework/catalogd/internal/garbagecollection" - "github.com/operator-framework/catalogd/internal/httputil" catalogdmetrics "github.com/operator-framework/catalogd/internal/metrics" "github.com/operator-framework/catalogd/internal/serverutil" "github.com/operator-framework/catalogd/internal/source" @@ -99,7 +99,7 @@ func main() { flag.StringVar(&certFile, "tls-cert", "", "The certificate file used for serving catalog contents over HTTPS. Requires tls-key.") flag.StringVar(&keyFile, "tls-key", "", "The key file used for serving catalog contents over HTTPS. Requires tls-cert.") flag.IntVar(&webhookPort, "webhook-server-port", 9443, "The port that the mutating webhook server serves at.") - flag.StringVar(&caCertDir, "ca-certs-dir", "", "The directory of TLS certificate to use for verifying HTTPS connections to the Catalogd and docker-registry web servers.") + flag.StringVar(&caCertDir, "ca-certs-dir", "", "The directory of CA certificate to use for verifying HTTPS connections to image registries.") opts := zap.Options{ Development: true, } @@ -178,16 +178,17 @@ func main() { os.Exit(1) } - certPool, err := httputil.NewCertPool(caCertDir, ctrl.Log.WithName("cert-pool")) - if err != nil { - setupLog.Error(err, "unable to create CA certificate pool") + unpackCacheBasePath := filepath.Join(cacheDir, source.UnpackCacheDir) + if err := os.MkdirAll(unpackCacheBasePath, 0770); err != nil { + setupLog.Error(err, "unable to create cache directory for unpacking") os.Exit(1) } - - unpacker, err := source.NewDefaultUnpacker(systemNamespace, cacheDir, certPool) - if err != nil { - setupLog.Error(err, "unable to create unpacker") - os.Exit(1) + unpacker := &source.ContainersImageRegistry{ + BaseCachePath: unpackCacheBasePath, + SourceContext: &types.SystemContext{ + OCICertPath: caCertDir, + DockerCertPath: caCertDir, + }, } var localStorage storage.Instance @@ -248,7 +249,7 @@ func main() { ctx := ctrl.SetupSignalHandler() gc := &garbagecollection.GarbageCollector{ - CachePath: filepath.Join(cacheDir, source.UnpackCacheDir), + CachePath: unpackCacheBasePath, Logger: ctrl.Log.WithName("garbage-collector"), MetadataClient: metaClient, Interval: gcInterval, diff --git a/config/base/rbac/role.yaml b/config/base/rbac/role.yaml index 05d37df4..40f4095c 100644 --- a/config/base/rbac/role.yaml +++ b/config/base/rbac/role.yaml @@ -4,26 +4,6 @@ kind: ClusterRole metadata: name: manager-role rules: -- apiGroups: - - "" - resources: - - pods - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - pods/log - verbs: - - get - - list - - watch - apiGroups: - olm.operatorframework.io resources: @@ -50,16 +30,3 @@ rules: - get - patch - update ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: manager-role - namespace: system -rules: -- apiGroups: - - "" - resources: - - secrets - verbs: - - get diff --git a/config/base/rbac/role_binding.yaml b/config/base/rbac/role_binding.yaml index 9093aeb1..a618c0e4 100644 --- a/config/base/rbac/role_binding.yaml +++ b/config/base/rbac/role_binding.yaml @@ -13,20 +13,3 @@ subjects: - kind: ServiceAccount name: controller-manager namespace: system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/name: catalogd - app.kubernetes.io/part-of: olm - name: manager-rolebinding - namespace: system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: manager-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/config/components/ca/kustomization.yaml b/config/components/ca/kustomization.yaml index 3d03bee8..113d2a95 100644 --- a/config/components/ca/kustomization.yaml +++ b/config/components/ca/kustomization.yaml @@ -3,3 +3,8 @@ kind: Component # No namespace is specified here, otherwise, it will overwrite _all_ the other namespaces! resources: - resources/issuers.yaml +patches: +- target: + kind: Deployment + name: controller-manager + path: patches/manager_deployment_cacerts.yaml diff --git a/config/components/ca/patches/manager_deployment_cacerts.yaml b/config/components/ca/patches/manager_deployment_cacerts.yaml new file mode 100644 index 00000000..d1155442 --- /dev/null +++ b/config/components/ca/patches/manager_deployment_cacerts.yaml @@ -0,0 +1,9 @@ +- op: add + path: /spec/template/spec/volumes/- + value: {"name":"olmv1-certificate", "secret":{"secretName":"catalogd-catalogserver-cert-git-version", "optional": false, "items": [{"key": "ca.crt", "path": "olm-ca.crt"}]}} +- op: add + path: /spec/template/spec/containers/1/volumeMounts/- + value: {"name":"olmv1-certificate", "readOnly": true, "mountPath":"/var/ca-certs/"} +- op: add + path: /spec/template/spec/containers/1/args/- + value: "--ca-certs-dir=/var/ca-certs" diff --git a/config/components/registries-conf/kustomization.yaml b/config/components/registries-conf/kustomization.yaml new file mode 100644 index 00000000..e4826242 --- /dev/null +++ b/config/components/registries-conf/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +namespace: olmv1-system +resources: +- registries_conf_configmap.yaml +patches: +- path: manager_e2e_registries_conf_patch.yaml diff --git a/config/components/registries-conf/manager_e2e_registries_conf_patch.yaml b/config/components/registries-conf/manager_e2e_registries_conf_patch.yaml new file mode 100644 index 00000000..7530f9b0 --- /dev/null +++ b/config/components/registries-conf/manager_e2e_registries_conf_patch.yaml @@ -0,0 +1,18 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + - name: manager + volumeMounts: + - name: e2e-registries-conf + mountPath: /etc/containers + volumes: + - name: e2e-registries-conf + configMap: + name: e2e-registries-conf diff --git a/config/components/registries-conf/registries_conf_configmap.yaml b/config/components/registries-conf/registries_conf_configmap.yaml new file mode 100644 index 00000000..3561bbe5 --- /dev/null +++ b/config/components/registries-conf/registries_conf_configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: e2e-registries-conf + namespace: system +data: + registries.conf: | + [[registry]] + prefix = "docker-registry.catalogd-e2e.svc:5000" + insecure = true + location = "docker-registry.catalogd-e2e.svc:5000" diff --git a/config/components/tls/patches/manager_deployment_certs.yaml b/config/components/tls/patches/manager_deployment_certs.yaml index 91f8f8c0..b0005f1c 100644 --- a/config/components/tls/patches/manager_deployment_certs.yaml +++ b/config/components/tls/patches/manager_deployment_certs.yaml @@ -10,6 +10,3 @@ - op: add path: /spec/template/spec/containers/1/args/- value: "--tls-key=/var/certs/tls.key" -- op: add - path: /spec/template/spec/containers/1/args/- - value: "--ca-certs-dir=/var/certs" diff --git a/config/overlays/e2e/kustomization.yaml b/config/overlays/e2e/kustomization.yaml new file mode 100644 index 00000000..dbfd7d73 --- /dev/null +++ b/config/overlays/e2e/kustomization.yaml @@ -0,0 +1,12 @@ +# kustomization file for all the e2e's +# DO NOT ADD A NAMESPACE HERE +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../../base/crd + - ../../base/rbac + - ../../base/manager +components: + - ../../components/tls + - ../../components/registries-conf + - ../../components/ca diff --git a/go.mod b/go.mod index 0639983f..902c01b4 100644 --- a/go.mod +++ b/go.mod @@ -5,17 +5,18 @@ go 1.22.5 require ( github.com/blang/semver/v4 v4.0.0 github.com/containerd/containerd v1.7.22 + github.com/containers/image/v5 v5.32.2 github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.20.2 github.com/klauspost/compress v1.17.9 github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/gomega v1.34.2 + github.com/opencontainers/go-digest v1.0.0 github.com/operator-framework/operator-registry v1.47.0 github.com/prometheus/client_golang v1.20.3 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - k8s.io/api v0.31.1 k8s.io/apiextensions-apiserver v0.31.1 k8s.io/apimachinery v0.31.1 k8s.io/apiserver v0.31.1 @@ -26,8 +27,11 @@ require ( ) require ( + github.com/BurntSushi/toml v1.4.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.12.5 // indirect + github.com/VividCortex/ewma v1.2.0 // indirect + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -36,23 +40,39 @@ require ( github.com/containerd/continuity v0.4.2 // indirect github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect + github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect + github.com/containers/ocicrypt v1.2.0 // indirect + github.com/containers/storage v1.55.0 // indirect + github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v27.2.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v27.1.1+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.2 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/go-git/go-git/v5 v5.11.0 // indirect + github.com/go-git/go-git/v5 v5.12.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -62,6 +82,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/mux v1.8.1 // indirect github.com/h2non/filetype v1.1.3 // indirect github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -70,29 +91,52 @@ require ( github.com/joelanford/ignore v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect + github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-sqlite3 v1.14.23 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/operator-framework/api v0.27.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/proglottis/gpgme v0.1.3 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect + github.com/sigstore/fulcio v1.4.5 // indirect + github.com/sigstore/rekor v1.3.6 // indirect + github.com/sigstore/sigstore v1.8.4 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cobra v1.8.1 // indirect + github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect + github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect github.com/vbatts/tar-split v0.11.5 // indirect + github.com/vbauerster/mpb/v8 v8.7.5 // indirect github.com/x448/float16 v0.8.4 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect + go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect @@ -112,7 +156,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.1.0 // indirect + k8s.io/api v0.31.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect diff --git a/go.sum b/go.sum index 4c6036b2..7169bb20 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,17 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.12.5 h1:bpTInLlDy/nDRWFVcefDZZ1+U8tS+rz3MxjKgu9boo0= github.com/Microsoft/hcsshim v0.12.5/go.mod h1:tIUGego4G1EN5Hb6KC90aDYiUI2dqLSTTOCjVNpOgZ8= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= @@ -27,27 +35,47 @@ github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5Z github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -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/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= +github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= +github.com/containers/image/v5 v5.32.2 h1:SzNE2Y6sf9b1GJoC8qjCuMBXwQrACFp4p0RK15+4gmQ= +github.com/containers/image/v5 v5.32.2/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk= +github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= +github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= +github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= +github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= +github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpffuhgg= +github.com/containers/storage v1.55.0/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM= +github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v27.2.0+incompatible h1:yHD1QEB1/0vr5eBNpu8tncu8gWxg8EydFPOSKHzXSMM= github.com/docker/cli v27.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +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/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 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/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= +github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -58,20 +86,38 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= 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/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +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-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= +github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +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-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/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -100,7 +146,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/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.3/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.9/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= @@ -114,6 +159,8 @@ github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAx github.com/google/uuid v1.1.2/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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj2I9TP8Jc+a7lge3QWn9DKE7NCwfc= @@ -124,6 +171,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= +github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= github.com/joelanford/ignore v0.1.0 h1:VawbTDeg5EL+PN7W8gxVzGerfGpVo3gFdR5ZAqnkYRk= github.com/joelanford/ignore v0.1.0/go.mod h1:Vb0PQMAQXK29fmiPjDukpO8I2NTcp1y8LbhFijD1/0o= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -134,20 +183,34 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 h1:aiPrFdHDCCvigNBCkOWj2lv9Bx5xDp210OANZEoiP0I= +github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0/go.mod h1:srVwm2N3DC/tWqQ+igZXDrmKlNRN8X/dmJ1wEZrv760= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +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/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0= +github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 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/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -157,6 +220,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +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/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/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= @@ -165,6 +230,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 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/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/operator-framework/api v0.27.0 h1:OrVaGKZJvbZo58HTv2guz7aURkhVKYhFqZ/6VpifiXI= github.com/operator-framework/api v0.27.0/go.mod h1:lg2Xx+S8NQWGYlEOvFwQvH46E5EK5IrAIL7HWfAhciM= github.com/operator-framework/operator-registry v1.47.0 h1:Imr7X/W6FmXczwpIOXfnX8d6Snr1dzwWxkMG+lLAfhg= @@ -174,6 +241,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/proglottis/gpgme v0.1.3 h1:Crxx0oz4LKB3QXc5Ea0J19K/3ICfy3ftr5exgUK1AU0= +github.com/proglottis/gpgme v0.1.3/go.mod h1:fPbW/EZ0LvwQtH8Hy7eixhp1eF3G39dtx7GUN+0Gmy0= github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -183,16 +252,28 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +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/sigstore/fulcio v1.4.5 h1:WWNnrOknD0DbruuZWCbN+86WRROpEl3Xts+WT2Ek1yc= +github.com/sigstore/fulcio v1.4.5/go.mod h1:oz3Qwlma8dWcSS/IENR/6SjbW4ipN0cxpRVfgdsjMU8= +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.4 h1:g4ICNpiENFnWxjmBzBDWUn62rNFeny/P77HUC8da32w= +github.com/sigstore/sigstore v1.8.4/go.mod h1:1jIKtkTFEeISen7en+ZPWdDHazqhxco/+v9CNjc7oNg= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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/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/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw= +github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6/go.mod h1:39R/xuhNgVhi+K0/zst4TLrJrVmbm6LVgl4A0+ZFS5M= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -205,23 +286,43 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +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/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 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/vbauerster/mpb/v8 v8.7.5 h1:hUF3zaNsuaBBwzEFoCvfuX3cpesQXZC0Phm/JcHZQ+c= +github.com/vbauerster/mpb/v8 v8.7.5/go.mod h1:bRCnR7K+mj5WXKsy0NWB6Or+wctYGvVwKn6huwvxKa0= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= +go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 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/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/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/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -257,7 +358,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h 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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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= @@ -277,7 +377,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -328,8 +427,9 @@ 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= -gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= -gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= diff --git a/internal/controllers/core/clustercatalog_controller.go b/internal/controllers/core/clustercatalog_controller.go index e1f6ee4a..7c8ccbfe 100644 --- a/internal/controllers/core/clustercatalog_controller.go +++ b/internal/controllers/core/clustercatalog_controller.go @@ -22,7 +22,6 @@ import ( "fmt" "time" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -56,9 +55,6 @@ type ClusterCatalogReconciler struct { //+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clustercatalogs,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clustercatalogs/status,verbs=get;update;patch //+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clustercatalogs/finalizers,verbs=update -//+kubebuilder:rbac:groups=core,resources=pods,verbs=create;update;patch;delete;get;list;watch -//+kubebuilder:rbac:groups=core,resources=pods/log,verbs=get;list;watch -//+kubebuilder:rbac:groups=core,namespace=system,resources=secrets,verbs=get; // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -66,8 +62,7 @@ type ClusterCatalogReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - // TODO: Where and when should we be logging errors and at which level? - _ = log.FromContext(ctx).WithName("catalogd-controller") + l := log.FromContext(ctx).WithName("catalogd-controller") existingCatsrc := v1alpha1.ClusterCatalog{} if err := r.Client.Get(ctx, req.NamespacedName, &existingCatsrc); err != nil { @@ -76,8 +71,8 @@ func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req ctrl.Reque reconciledCatsrc := existingCatsrc.DeepCopy() res, reconcileErr := r.reconcile(ctx, reconciledCatsrc) - var unrecov *catalogderrors.Unrecoverable - if errors.As(reconcileErr, &unrecov) { + if errors.As(reconcileErr, &catalogderrors.Unrecoverable{}) { + l.Error(reconcileErr, "unrecoverable reconcile error") reconcileErr = nil } @@ -105,7 +100,6 @@ func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req ctrl.Reque func (r *ClusterCatalogReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.ClusterCatalog{}). - Owns(&corev1.Pod{}). Complete(r) } diff --git a/internal/controllers/core/clustercatalog_controller_test.go b/internal/controllers/core/clustercatalog_controller_test.go index ebf7b6d5..c5edb742 100644 --- a/internal/controllers/core/clustercatalog_controller_test.go +++ b/internal/controllers/core/clustercatalog_controller_test.go @@ -84,12 +84,13 @@ func TestCatalogdControllerReconcile(t *testing.T) { name string catalog *catalogdv1alpha1.ClusterCatalog shouldErr bool + shouldPanic bool expectedCatalog *catalogdv1alpha1.ClusterCatalog source source.Unpacker store storage.Instance }{ { - name: "invalid source type, returns error", + name: "invalid source type, panics", source: &MockSource{}, store: &MockStore{}, catalog: &catalogdv1alpha1.ClusterCatalog{ @@ -103,7 +104,7 @@ func TestCatalogdControllerReconcile(t *testing.T) { }, }, }, - shouldErr: true, + shouldPanic: true, expectedCatalog: &catalogdv1alpha1.ClusterCatalog{ ObjectMeta: metav1.ObjectMeta{ Name: "catalog", @@ -518,15 +519,17 @@ func TestCatalogdControllerReconcile(t *testing.T) { } { t.Run(tt.name, func(t *testing.T) { reconciler := &ClusterCatalogReconciler{ - Client: nil, - Unpacker: source.NewUnpacker( - map[catalogdv1alpha1.SourceType]source.Unpacker{ - catalogdv1alpha1.SourceTypeImage: tt.source, - }, - ), - Storage: tt.store, + Client: nil, + Unpacker: tt.source, + Storage: tt.store, } ctx := context.Background() + + if tt.shouldPanic { + assert.Panics(t, func() { _, _ = reconciler.reconcile(ctx, tt.catalog) }) + return + } + res, err := reconciler.reconcile(ctx, tt.catalog) assert.Equal(t, ctrl.Result{}, res) @@ -585,14 +588,10 @@ func TestPollingRequeue(t *testing.T) { t.Run(name, func(t *testing.T) { reconciler := &ClusterCatalogReconciler{ Client: nil, - Unpacker: source.NewUnpacker( - map[catalogdv1alpha1.SourceType]source.Unpacker{ - catalogdv1alpha1.SourceTypeImage: &MockSource{result: &source.Result{ - State: source.StateUnpacked, - FS: &fstest.MapFS{}, - }}, - }, - ), + Unpacker: &MockSource{result: &source.Result{ + State: source.StateUnpacked, + FS: &fstest.MapFS{}, + }}, Storage: &MockStore{}, } res, _ := reconciler.reconcile(context.Background(), tc.catalog) diff --git a/internal/errors/unrecoverable.go b/internal/errors/unrecoverable.go index c212422b..c28311d3 100644 --- a/internal/errors/unrecoverable.go +++ b/internal/errors/unrecoverable.go @@ -7,6 +7,6 @@ type Unrecoverable struct { error } -func NewUnrecoverable(err error) *Unrecoverable { - return &Unrecoverable{err} +func NewUnrecoverable(err error) Unrecoverable { + return Unrecoverable{err} } diff --git a/internal/httputil/certutil.go b/internal/httputil/certutil.go deleted file mode 100644 index 607189da..00000000 --- a/internal/httputil/certutil.go +++ /dev/null @@ -1,57 +0,0 @@ -package httputil - -import ( - "crypto/x509" - "fmt" - "os" - "path/filepath" - - "github.com/go-logr/logr" -) - -// Should share code from operator-controller. -// see: https://issues.redhat.com/browse/OPRUN-3535 -func NewCertPool(caDir string, log logr.Logger) (*x509.CertPool, error) { - caCertPool, err := x509.SystemCertPool() - if err != nil { - return nil, err - } - if caDir == "" { - return caCertPool, nil - } - - dirEntries, err := os.ReadDir(caDir) - if err != nil { - return nil, err - } - count := 0 - - for _, e := range dirEntries { - file := filepath.Join(caDir, e.Name()) - // These might be symlinks pointing to directories, so use Stat() to resolve - fi, err := os.Stat(file) - if err != nil { - return nil, err - } - if fi.IsDir() { - log.Info("skip directory", "name", e.Name()) - continue - } - log.Info("load certificate", "name", e.Name()) - data, err := os.ReadFile(file) - if err != nil { - return nil, fmt.Errorf("error reading cert file %q: %w", file, err) - } - - if ok := caCertPool.AppendCertsFromPEM(data); ok { - count++ - } - } - - // Found no certs! - if count == 0 { - return nil, fmt.Errorf("no certificates found in %q", caDir) - } - - return caCertPool, nil -} diff --git a/internal/httputil/certutil_test.go b/internal/httputil/certutil_test.go deleted file mode 100644 index 87e7e465..00000000 --- a/internal/httputil/certutil_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package httputil - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "math/big" - "os" - "testing" - "time" - - "github.com/go-logr/logr/testr" - "github.com/stretchr/testify/require" -) - -func TestNewCertPool(t *testing.T) { - t.Parallel() - - // set up our CA certificate - ca := &x509.Certificate{ - SerialNumber: big.NewInt(2019), - Subject: pkix.Name{ - Organization: []string{"Company, INC."}, - Country: []string{"US"}, - Province: []string{""}, - Locality: []string{"San Francisco"}, - StreetAddress: []string{"Golden Gate Bridge"}, - PostalCode: []string{"94016"}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), - IsCA: true, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - - // create our private and public key - caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) - require.NoError(t, err) - - // create the CA - caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) - require.NoError(t, err) - - // pem encode - err = os.MkdirAll("testdata/newCertPool/subfolder", 0700) - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll("testdata/newCertPool")) - }) - - caPEM, err := os.Create("testdata/newCertPool/my.pem") - require.NoError(t, err) - err = pem.Encode(caPEM, &pem.Block{ - Type: "CERTIFICATE", - Bytes: caBytes, - }) - require.NoError(t, err) - - _, err = NewCertPool("testdata/newCertPool", testr.New(t)) - require.NoError(t, err) -} - -func Test_newCertPool_empty(t *testing.T) { - err := os.MkdirAll("testdata/newCertPoolEmpty", 0700) - require.NoError(t, err) - - _, err = NewCertPool("testdata/newCertPoolEmpty", testr.New(t)) - require.EqualError(t, err, `no certificates found in "testdata/newCertPoolEmpty"`) -} diff --git a/internal/source/containers_image.go b/internal/source/containers_image.go new file mode 100644 index 00000000..807903e7 --- /dev/null +++ b/internal/source/containers_image.go @@ -0,0 +1,404 @@ +package source + +import ( + "archive/tar" + "context" + "errors" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + "time" + + "github.com/containerd/containerd/archive" + "github.com/containers/image/v5/copy" + "github.com/containers/image/v5/docker" + "github.com/containers/image/v5/docker/reference" + "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/oci/layout" + "github.com/containers/image/v5/pkg/blobinfocache/none" + "github.com/containers/image/v5/pkg/compression" + "github.com/containers/image/v5/signature" + "github.com/containers/image/v5/types" + "github.com/go-logr/logr" + "github.com/opencontainers/go-digest" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/log" + + catalogdv1alpha1 "github.com/operator-framework/catalogd/api/core/v1alpha1" + catalogderrors "github.com/operator-framework/catalogd/internal/errors" +) + +const ConfigDirLabel = "operators.operatorframework.io.index.configs.v1" + +type ContainersImageRegistry struct { + BaseCachePath string + SourceContext *types.SystemContext +} + +func (i *ContainersImageRegistry) Unpack(ctx context.Context, catalog *catalogdv1alpha1.ClusterCatalog) (*Result, error) { + l := log.FromContext(ctx) + + if catalog.Spec.Source.Type != catalogdv1alpha1.SourceTypeImage { + panic(fmt.Sprintf("programmer error: source type %q is unable to handle specified catalog source type %q", catalogdv1alpha1.SourceTypeImage, catalog.Spec.Source.Type)) + } + + if catalog.Spec.Source.Image == nil { + return nil, catalogderrors.NewUnrecoverable(fmt.Errorf("error parsing catalog, catalog %s has a nil image source", catalog.Name)) + } + + ////////////////////////////////////////////////////// + // + // Resolve a canonical reference for the image. + // + ////////////////////////////////////////////////////// + imgRef, canonicalRef, specIsCanonical, err := resolveReferences(ctx, catalog.Spec.Source.Image.Ref, i.SourceContext) + if err != nil { + return nil, err + } + + ////////////////////////////////////////////////////// + // + // Check if the image is already unpacked. If it is, + // return the unpacked directory. + // + ////////////////////////////////////////////////////// + unpackPath := i.unpackPath(catalog.Name, canonicalRef.Digest()) + if unpackStat, err := os.Stat(unpackPath); err == nil { + if !unpackStat.IsDir() { + panic(fmt.Sprintf("unexpected file at unpack path %q: expected a directory", unpackPath)) + } + l.Info("image already unpacked", "ref", imgRef.String(), "digest", canonicalRef.Digest().String()) + return successResult(catalog, unpackPath, canonicalRef, metav1.NewTime(unpackStat.ModTime())), nil + } + + ////////////////////////////////////////////////////// + // + // Create a docker reference for the source and an OCI + // layout reference for the destination, where we will + // temporarily store the image in order to unpack it. + // + // We use the OCI layout as a temporary storage because + // copy.Image can concurrently pull all the layers. + // + ////////////////////////////////////////////////////// + dockerRef, err := docker.NewReference(canonicalRef) + if err != nil { + return nil, fmt.Errorf("error creating source reference: %w", err) + } + + layoutDir, err := os.MkdirTemp("", fmt.Sprintf("oci-layout-%s", catalog.Name)) + if err != nil { + return nil, fmt.Errorf("error creating temporary directory: %w", err) + } + defer func() { + if err := os.RemoveAll(layoutDir); err != nil { + l.Error(err, "error removing temporary OCI layout directory") + } + }() + + layoutRef, err := layout.NewReference(layoutDir, canonicalRef.String()) + if err != nil { + return nil, fmt.Errorf("error creating reference: %w", err) + } + + ////////////////////////////////////////////////////// + // + // Load an image signature policy and build + // a policy context for the image pull. + // + ////////////////////////////////////////////////////// + policyContext, err := loadPolicyContext(i.SourceContext, l) + if err != nil { + return nil, fmt.Errorf("error loading policy context: %w", err) + } + defer func() { + if err := policyContext.Destroy(); err != nil { + l.Error(err, "error destroying policy context") + } + }() + + ////////////////////////////////////////////////////// + // + // Pull the image from the source to the destination + // + ////////////////////////////////////////////////////// + if _, err := copy.Image(ctx, policyContext, layoutRef, dockerRef, ©.Options{ + SourceCtx: i.SourceContext, + }); err != nil { + return nil, fmt.Errorf("error copying image: %w", err) + } + l.Info("pulled image", "ref", imgRef.String(), "digest", canonicalRef.Digest().String()) + + ////////////////////////////////////////////////////// + // + // Mount the image we just pulled + // + ////////////////////////////////////////////////////// + if err := i.unpackImage(ctx, unpackPath, layoutRef, specIsCanonical); err != nil { + if cleanupErr := deleteRecursive(unpackPath); cleanupErr != nil { + err = errors.Join(err, cleanupErr) + } + return nil, fmt.Errorf("error unpacking image: %w", err) + } + + ////////////////////////////////////////////////////// + // + // Delete other images. They are no longer needed. + // + ////////////////////////////////////////////////////// + if err := i.deleteOtherImages(catalog.Name, canonicalRef.Digest()); err != nil { + return nil, fmt.Errorf("error deleting old images: %w", err) + } + + return successResult(catalog, unpackPath, canonicalRef, metav1.Now()), nil +} + +func successResult(catalog *catalogdv1alpha1.ClusterCatalog, unpackPath string, canonicalRef reference.Canonical, lastUnpacked metav1.Time) *Result { + return &Result{ + FS: os.DirFS(unpackPath), + ResolvedSource: &catalogdv1alpha1.ResolvedCatalogSource{ + Type: catalogdv1alpha1.SourceTypeImage, + Image: &catalogdv1alpha1.ResolvedImageSource{ + Ref: catalog.Spec.Source.Image.Ref, + ResolvedRef: canonicalRef.String(), + LastPollAttempt: metav1.Time{Time: time.Now()}, + LastUnpacked: lastUnpacked, + }, + }, + State: StateUnpacked, + Message: fmt.Sprintf("unpacked %q successfully", canonicalRef), + } +} + +func (i *ContainersImageRegistry) Cleanup(_ context.Context, catalog *catalogdv1alpha1.ClusterCatalog) error { + return deleteRecursive(i.catalogPath(catalog.Name)) +} + +func (i *ContainersImageRegistry) catalogPath(catalogName string) string { + return filepath.Join(i.BaseCachePath, catalogName) +} + +func (i *ContainersImageRegistry) unpackPath(catalogName string, digest digest.Digest) string { + return filepath.Join(i.catalogPath(catalogName), digest.String()) +} + +func resolveReferences(ctx context.Context, ref string, sourceContext *types.SystemContext) (reference.Named, reference.Canonical, bool, error) { + imgRef, err := reference.ParseNamed(ref) + if err != nil { + return nil, nil, false, catalogderrors.NewUnrecoverable(fmt.Errorf("error parsing image reference %q: %w", ref, err)) + } + + canonicalRef, isCanonical, err := resolveCanonicalRef(ctx, imgRef, sourceContext) + if err != nil { + return nil, nil, false, fmt.Errorf("error resolving canonical reference: %w", err) + } + return imgRef, canonicalRef, isCanonical, nil +} + +func resolveCanonicalRef(ctx context.Context, imgRef reference.Named, imageCtx *types.SystemContext) (reference.Canonical, bool, error) { + if canonicalRef, ok := imgRef.(reference.Canonical); ok { + return canonicalRef, true, nil + } + + srcRef, err := docker.NewReference(imgRef) + if err != nil { + return nil, false, catalogderrors.NewUnrecoverable(fmt.Errorf("error creating reference: %w", err)) + } + + imgSrc, err := srcRef.NewImageSource(ctx, imageCtx) + if err != nil { + return nil, false, fmt.Errorf("error creating image source: %w", err) + } + defer imgSrc.Close() + + imgManifestData, _, err := imgSrc.GetManifest(ctx, nil) + if err != nil { + return nil, false, fmt.Errorf("error getting manifest: %w", err) + } + imgDigest, err := manifest.Digest(imgManifestData) + if err != nil { + return nil, false, fmt.Errorf("error getting digest of manifest: %w", err) + } + canonicalRef, err := reference.WithDigest(reference.TrimNamed(imgRef), imgDigest) + if err != nil { + return nil, false, fmt.Errorf("error creating canonical reference: %w", err) + } + return canonicalRef, false, nil +} + +func loadPolicyContext(sourceContext *types.SystemContext, l logr.Logger) (*signature.PolicyContext, error) { + policy, err := signature.DefaultPolicy(sourceContext) + if os.IsNotExist(err) { + l.Info("no default policy found, using insecure policy") + policy, err = signature.NewPolicyFromBytes([]byte(`{"default":[{"type":"insecureAcceptAnything"}]}`)) + } + if err != nil { + return nil, fmt.Errorf("error loading default policy: %w", err) + } + return signature.NewPolicyContext(policy) +} + +func (i *ContainersImageRegistry) unpackImage(ctx context.Context, unpackPath string, imageReference types.ImageReference, specIsCanonical bool) error { + img, err := imageReference.NewImage(ctx, i.SourceContext) + if err != nil { + return fmt.Errorf("error reading image: %w", err) + } + defer func() { + if err := img.Close(); err != nil { + panic(err) + } + }() + + layoutSrc, err := imageReference.NewImageSource(ctx, i.SourceContext) + if err != nil { + return fmt.Errorf("error creating image source: %w", err) + } + + cfg, err := img.OCIConfig(ctx) + if err != nil { + return fmt.Errorf("error parsing image config: %w", err) + } + + dirToUnpack, ok := cfg.Config.Labels[ConfigDirLabel] + if !ok { + // If the spec is a tagged ref, retries could end up resolving a new digest, where the label + // might show up. If the spec is canonical, no amount of retries will make the label appear. + // Therefore, we treat the error as unrecoverable if the reference from the spec is canonical. + return wrapUnrecoverable(fmt.Errorf("catalog image is missing the required label %q", ConfigDirLabel), specIsCanonical) + } + + if err := os.MkdirAll(unpackPath, 0700); err != nil { + return fmt.Errorf("error creating unpack directory: %w", err) + } + l := log.FromContext(ctx) + l.Info("unpacking image", "path", unpackPath) + for i, layerInfo := range img.LayerInfos() { + if err := func() error { + layerReader, _, err := layoutSrc.GetBlob(ctx, layerInfo, none.NoCache) + if err != nil { + return fmt.Errorf("error getting blob for layer[%d]: %w", i, err) + } + defer layerReader.Close() + + if err := applyLayer(ctx, unpackPath, dirToUnpack, layerReader); err != nil { + return fmt.Errorf("error applying layer[%d]: %w", i, err) + } + l.Info("applied layer", "layer", i) + return nil + }(); err != nil { + return errors.Join(err, deleteRecursive(unpackPath)) + } + } + if err := setReadOnlyRecursive(unpackPath); err != nil { + return fmt.Errorf("error making unpack directory read-only: %w", err) + } + return nil +} + +func applyLayer(ctx context.Context, destPath string, srcPath string, layer io.ReadCloser) error { + decompressed, _, err := compression.AutoDecompress(layer) + if err != nil { + return fmt.Errorf("auto-decompress failed: %w", err) + } + defer decompressed.Close() + + _, err = archive.Apply(ctx, destPath, decompressed, archive.WithFilter(applyLayerFilter(srcPath))) + return err +} + +func applyLayerFilter(srcPath string) archive.Filter { + cleanSrcPath := path.Clean(strings.TrimPrefix(srcPath, "/")) + return func(h *tar.Header) (bool, error) { + h.Uid = os.Getuid() + h.Gid = os.Getgid() + h.Mode |= 0700 + + cleanName := path.Clean(strings.TrimPrefix(h.Name, "/")) + relPath, err := filepath.Rel(cleanSrcPath, cleanName) + if err != nil { + return false, fmt.Errorf("error getting relative path: %w", err) + } + return relPath != ".." && !strings.HasPrefix(relPath, "../"), nil + } +} + +func (i *ContainersImageRegistry) deleteOtherImages(catalogName string, digestToKeep digest.Digest) error { + catalogPath := i.catalogPath(catalogName) + imgDirs, err := os.ReadDir(catalogPath) + if err != nil { + return fmt.Errorf("error reading image directories: %w", err) + } + for _, imgDir := range imgDirs { + if imgDir.Name() == digestToKeep.String() { + continue + } + imgDirPath := filepath.Join(catalogPath, imgDir.Name()) + if err := deleteRecursive(imgDirPath); err != nil { + return fmt.Errorf("error removing image directory: %w", err) + } + } + return nil +} + +func setReadOnlyRecursive(root string) error { + if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + + fi, err := d.Info() + if err != nil { + return err + } + + if err := func() error { + switch typ := fi.Mode().Type(); typ { + case os.ModeSymlink: + // do not follow symlinks + // 1. if they resolve to other locations in the root, we'll find them anyway + // 2. if they resolve to other locations outside the root, we don't want to change their permissions + return nil + case os.ModeDir: + return os.Chmod(path, 0500) + case 0: // regular file + return os.Chmod(path, 0400) + default: + return fmt.Errorf("refusing to change ownership of file %q with type %v", path, typ.String()) + } + }(); err != nil { + return err + } + return nil + }); err != nil { + return fmt.Errorf("error making catalog cache read-only: %w", err) + } + return nil +} + +func deleteRecursive(root string) error { + if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + return nil + } + if err := os.Chmod(path, 0700); err != nil { + return err + } + return nil + }); err != nil { + return fmt.Errorf("error making catalog cache writable for deletion: %w", err) + } + return os.RemoveAll(root) +} + +func wrapUnrecoverable(err error, isUnrecoverable bool) error { + if !isUnrecoverable { + return err + } + return catalogderrors.NewUnrecoverable(err) +} diff --git a/internal/source/containers_image_internal_test.go b/internal/source/containers_image_internal_test.go new file mode 100644 index 00000000..0c3ba128 --- /dev/null +++ b/internal/source/containers_image_internal_test.go @@ -0,0 +1,130 @@ +package source + +import ( + "archive/tar" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestContainersImage_applyLayerFilter(t *testing.T) { + type testCase struct { + name string + srcPaths []string + tarHeaders []tar.Header + assertion func(*tar.Header, bool, error) + } + for _, tc := range []testCase{ + { + name: "everything found when srcPaths represent root", + srcPaths: []string{"", "/"}, + tarHeaders: []tar.Header{ + { + Name: "file", + }, + { + Name: "/file", + }, + { + Name: "/nested/file", + }, + { + Name: "/deeply/nested/file", + }, + }, + assertion: func(tarHeader *tar.Header, keep bool, err error) { + assert.True(t, keep) + assert.NoError(t, err) + }, + }, + { + name: "nothing found outside of srcPath", + srcPaths: []string{"source"}, + tarHeaders: []tar.Header{ + { + Name: "elsewhere", + }, + { + Name: "/elsewhere", + }, + { + Name: "/nested/elsewhere", + }, + { + Name: "/deeply/nested/elsewhere", + }, + }, + assertion: func(tarHeader *tar.Header, keep bool, err error) { + assert.False(t, keep) + assert.NoError(t, err) + }, + }, + { + name: "absolute paths are trimmed", + srcPaths: []string{"source", "/source"}, + tarHeaders: []tar.Header{ + { + Name: "source", + }, + { + Name: "/source", + }, + { + Name: "source/nested/elsewhere", + }, + { + Name: "/source/nested/elsewhere", + }, + { + Name: "source/deeply/nested/elsewhere", + }, + { + Name: "/source/deeply/nested/elsewhere", + }, + }, + assertion: func(tarHeader *tar.Header, keep bool, err error) { + assert.True(t, keep) + assert.NoError(t, err) + }, + }, + { + name: "up level source paths are not supported", + srcPaths: []string{"../not-supported"}, + tarHeaders: []tar.Header{ + { + Name: "anything", + }, + }, + assertion: func(tarHeader *tar.Header, keep bool, err error) { + assert.False(t, keep) + assert.ErrorContains(t, err, "error getting relative path") + }, + }, + { + name: "up level tar headers are not supported", + srcPaths: []string{"fine"}, + tarHeaders: []tar.Header{ + { + Name: "../not-supported", + }, + { + Name: "../fine", + }, + }, + assertion: func(tarHeader *tar.Header, keep bool, err error) { + assert.False(t, keep) + assert.NoError(t, err) + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + for _, srcPath := range tc.srcPaths { + f := applyLayerFilter(srcPath) + for _, tarHeader := range tc.tarHeaders { + keep, err := f(&tarHeader) + tc.assertion(&tarHeader, keep, err) + } + } + }) + } +} diff --git a/internal/source/image_registry_client_test.go b/internal/source/containers_image_test.go similarity index 88% rename from internal/source/image_registry_client_test.go rename to internal/source/containers_image_test.go index 2342bfac..b7ccaff6 100644 --- a/internal/source/image_registry_client_test.go +++ b/internal/source/containers_image_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/containers/image/v5/types" "github.com/go-logr/logr/funcr" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/registry" @@ -165,13 +166,6 @@ func TestImageRegistry(t *testing.T) { }, }, }, - Status: v1alpha1.ClusterCatalogStatus{ - ResolvedSource: &v1alpha1.ResolvedCatalogSource{ - Image: &v1alpha1.ResolvedImageSource{ - LastUnpacked: metav1.Time{Time: time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC)}, - }, - }, - }, }, wantErr: false, image: func() v1.Image { @@ -198,13 +192,6 @@ func TestImageRegistry(t *testing.T) { }, }, }, - Status: v1alpha1.ClusterCatalogStatus{ - ResolvedSource: &v1alpha1.ResolvedCatalogSource{ - Image: &v1alpha1.ResolvedImageSource{ - LastUnpacked: metav1.Time{Time: time.Date(2000, 2, 1, 12, 30, 0, 1, time.UTC)}, - }, - }, - }, }, wantErr: false, digestAlreadyExists: true, @@ -231,13 +218,6 @@ func TestImageRegistry(t *testing.T) { }, }, }, - Status: v1alpha1.ClusterCatalogStatus{ - ResolvedSource: &v1alpha1.ResolvedCatalogSource{ - Image: &v1alpha1.ResolvedImageSource{ - LastUnpacked: metav1.Time{Time: time.Date(2000, 2, 1, 12, 30, 0, 2, time.UTC)}, - }, - }, - }, }, wantErr: false, oldDigestExists: true, @@ -331,8 +311,12 @@ func TestImageRegistry(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) testCache := t.TempDir() - imgReg := &source.ImageRegistry{ + imgReg := &source.ContainersImageRegistry{ BaseCachePath: testCache, + SourceContext: &types.SystemContext{ + OCIInsecureSkipTLSVerify: true, + DockerInsecureSkipTLSVerify: types.OptionalBoolTrue, + }, } // Create a logger with a simple function-based LogSink that writes to the buffer @@ -358,9 +342,13 @@ func TestImageRegistry(t *testing.T) { require.NoError(t, err) // If an old digest should exist in the cache, create one + oldDigestDir := filepath.Join(testCache, tt.catalog.Name, "olddigest") + var oldDigestModTime time.Time if tt.oldDigestExists { - err = os.MkdirAll(filepath.Join(testCache, tt.catalog.Name, "olddigest"), os.ModePerm) + require.NoError(t, os.MkdirAll(oldDigestDir, os.ModePerm)) + oldDigestDirStat, err := os.Stat(oldDigestDir) require.NoError(t, err) + oldDigestModTime = oldDigestDirStat.ModTime() } var digest v1.Hash @@ -372,7 +360,7 @@ func TestImageRegistry(t *testing.T) { // if the digest should already exist in the cache, create it if tt.digestAlreadyExists { - err = os.MkdirAll(filepath.Join(testCache, tt.catalog.Name, digest.Hex), os.ModePerm) + err = os.MkdirAll(filepath.Join(testCache, tt.catalog.Name, digest.String()), os.ModePerm) require.NoError(t, err) } @@ -393,20 +381,26 @@ func TestImageRegistry(t *testing.T) { rs, err := imgReg.Unpack(ctx, tt.catalog) if !tt.wantErr { - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, fmt.Sprintf("%s@sha256:%s", imgName.Context().Name(), digest.Hex), rs.ResolvedSource.Image.ResolvedRef) assert.Equal(t, source.StateUnpacked, rs.State) - assert.DirExists(t, filepath.Join(testCache, tt.catalog.Name, digest.Hex)) + + unpackDir := filepath.Join(testCache, tt.catalog.Name, digest.String()) + assert.DirExists(t, unpackDir) + unpackDirStat, err := os.Stat(unpackDir) + require.NoError(t, err) + entries, err := os.ReadDir(filepath.Join(testCache, tt.catalog.Name)) require.NoError(t, err) assert.Len(t, entries, 1) // If the digest should already exist check that we actually hit it if tt.digestAlreadyExists { - assert.Contains(t, buf.String(), "found image in filesystem cache") - assert.Equal(t, tt.catalog.Status.ResolvedSource.Image.LastUnpacked, rs.ResolvedSource.Image.LastUnpacked) + assert.Contains(t, buf.String(), "image already unpacked") + assert.Equal(t, rs.ResolvedSource.Image.LastUnpacked.Time, unpackDirStat.ModTime()) } else if tt.oldDigestExists { - assert.NotContains(t, buf.String(), "found image in filesystem cache") - assert.NotEqual(t, tt.catalog.Status.ResolvedSource.Image.LastUnpacked, rs.ResolvedSource.Image.LastUnpacked) + assert.NotContains(t, buf.String(), "image already unpacked") + assert.NotEqual(t, rs.ResolvedSource.Image.LastUnpacked.Time, oldDigestModTime) + assert.NoDirExists(t, oldDigestDir) } else { require.NotNil(t, rs.ResolvedSource.Image.LastUnpacked) require.NotNil(t, rs.ResolvedSource.Image) @@ -414,8 +408,7 @@ func TestImageRegistry(t *testing.T) { } } else { assert.Error(t, err) - var unrecov *catalogderrors.Unrecoverable - isUnrecov := errors.As(err, &unrecov) + isUnrecov := errors.As(err, &catalogderrors.Unrecoverable{}) assert.Equal(t, tt.unrecoverable, isUnrecov, "expected unrecoverable %v, got %v", tt.unrecoverable, isUnrecov) } }) @@ -433,7 +426,7 @@ func TestImageRegistryMissingLabelConsistentFailure(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) testCache := t.TempDir() - imgReg := &source.ImageRegistry{ + imgReg := &source.ContainersImageRegistry{ BaseCachePath: testCache, } diff --git a/internal/source/image_registry_client.go b/internal/source/image_registry_client.go deleted file mode 100644 index cb8aa029..00000000 --- a/internal/source/image_registry_client.go +++ /dev/null @@ -1,205 +0,0 @@ -package source - -import ( - "archive/tar" - "context" - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "io/fs" - "net/http" - "os" - "path/filepath" - "strings" - "time" - - "github.com/containerd/containerd/archive" - "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/remote" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apimacherrors "k8s.io/apimachinery/pkg/util/errors" - "sigs.k8s.io/controller-runtime/pkg/log" - - catalogdv1alpha1 "github.com/operator-framework/catalogd/api/core/v1alpha1" - catalogderrors "github.com/operator-framework/catalogd/internal/errors" -) - -// TODO: Make asynchronous - -type ImageRegistry struct { - BaseCachePath string - AuthNamespace string - CertPool *x509.CertPool -} - -const ConfigDirLabel = "operators.operatorframework.io.index.configs.v1" - -func (i *ImageRegistry) Unpack(ctx context.Context, catalog *catalogdv1alpha1.ClusterCatalog) (*Result, error) { - l := log.FromContext(ctx) - if catalog.Spec.Source.Type != catalogdv1alpha1.SourceTypeImage { - panic(fmt.Sprintf("programmer error: source type %q is unable to handle specified catalog source type %q", catalogdv1alpha1.SourceTypeImage, catalog.Spec.Source.Type)) - } - - if catalog.Spec.Source.Image == nil { - return nil, catalogderrors.NewUnrecoverable(fmt.Errorf("error parsing catalog, catalog %s has a nil image source", catalog.Name)) - } - - imgRef, err := name.ParseReference(catalog.Spec.Source.Image.Ref) - if err != nil { - return nil, catalogderrors.NewUnrecoverable(fmt.Errorf("error parsing image reference: %w", err)) - } - - var remoteOpts []remote.Option - - // Set up the TLS transport - tlsTransport := remote.DefaultTransport.(*http.Transport).Clone() - if tlsTransport.TLSClientConfig == nil { - tlsTransport.TLSClientConfig = &tls.Config{ - InsecureSkipVerify: false, - MinVersion: tls.VersionTLS12, - } // nolint:gosec - } - if i.CertPool != nil { - tlsTransport.TLSClientConfig.RootCAs = i.CertPool - } - remoteOpts = append(remoteOpts, remote.WithTransport(tlsTransport)) - - digestHex, err := resolveDigest(imgRef, remoteOpts...) - if err != nil { - return nil, fmt.Errorf("error fetching image descriptor: %w", err) - } - l.V(1).Info("resolved image descriptor", "digest", digestHex) - - unpackPath := filepath.Join(i.BaseCachePath, catalog.Name, digestHex) - resolvedRef := fmt.Sprintf("%s@sha256:%s", imgRef.Context().Name(), digestHex) - if stat, err := os.Stat(unpackPath); err == nil && stat.IsDir() { - l.V(1).Info("found image in filesystem cache", "digest", digestHex) - lastUnpacked := metav1.Time{Time: time.Now()} - if catalog.Status.ResolvedSource != nil && catalog.Status.ResolvedSource.Image != nil { - lastUnpacked = catalog.Status.ResolvedSource.Image.LastUnpacked - } - return unpackedResult(os.DirFS(unpackPath), catalog, resolvedRef, lastUnpacked), nil - } - - if _, err = os.Stat(unpackPath); errors.Is(err, os.ErrNotExist) { //nolint: nestif - // Ensure any previous unpacked catalog is cleaned up before unpacking the new catalog. - if err := i.Cleanup(ctx, catalog); err != nil { - return nil, fmt.Errorf("error cleaning up catalog cache: %w", err) - } - - if err = os.MkdirAll(unpackPath, 0700); err != nil { - return nil, fmt.Errorf("error creating unpack path: %w", err) - } - - if err = unpackImage(ctx, imgRef, unpackPath, remoteOpts...); err != nil { - cleanupErr := os.RemoveAll(unpackPath) - if cleanupErr != nil { - err = apimacherrors.NewAggregate( - []error{ - err, - fmt.Errorf("error cleaning up unpack path after unpack failed: %w", cleanupErr), - }, - ) - } - _, isDigest := imgRef.(name.Digest) - return nil, wrapUnrecoverable(fmt.Errorf("error unpacking image: %w", err), isDigest) - } - } else if err != nil { - return nil, fmt.Errorf("error checking if image is in filesystem cache: %w", err) - } - - return unpackedResult(os.DirFS(unpackPath), catalog, resolvedRef, metav1.Time{Time: time.Now()}), nil -} - -func wrapUnrecoverable(err error, isUnrecoverable bool) error { - if isUnrecoverable { - return catalogderrors.NewUnrecoverable(err) - } - return err -} - -func (i *ImageRegistry) Cleanup(_ context.Context, catalog *catalogdv1alpha1.ClusterCatalog) error { - return os.RemoveAll(filepath.Join(i.BaseCachePath, catalog.Name)) -} - -func unpackedResult(fsys fs.FS, catalog *catalogdv1alpha1.ClusterCatalog, ref string, lastUnpacked metav1.Time) *Result { - return &Result{ - FS: fsys, - ResolvedSource: &catalogdv1alpha1.ResolvedCatalogSource{ - Type: catalogdv1alpha1.SourceTypeImage, - Image: &catalogdv1alpha1.ResolvedImageSource{ - Ref: catalog.Spec.Source.Image.Ref, - ResolvedRef: ref, - LastPollAttempt: metav1.Time{Time: time.Now()}, - LastUnpacked: lastUnpacked, - }, - }, - State: StateUnpacked, - } -} - -// resolveDigest returns hex value of the digest for image reference -func resolveDigest(imgRef name.Reference, remoteOpts ...remote.Option) (string, error) { - digest, isDigest := imgRef.(name.Digest) - if isDigest { - digestHex := strings.TrimPrefix(digest.DigestStr(), "sha256:") - // If the reference is already a digest - return without making a network call - return digestHex, nil - } - - imgDesc, err := remote.Head(imgRef, remoteOpts...) - if err != nil { - return "", err - } - - return imgDesc.Digest.Hex, nil -} - -// unpackImage unpacks a catalog image reference to the provided unpackPath, -// returning an error if any errors are encountered along the way. -func unpackImage(ctx context.Context, imgRef name.Reference, unpackPath string, remoteOpts ...remote.Option) error { - img, err := remote.Image(imgRef, remoteOpts...) - if err != nil { - return fmt.Errorf("error fetching remote image %q: %w", imgRef.Name(), err) - } - - cfgFile, err := img.ConfigFile() - if err != nil { - return fmt.Errorf("error parsing remote image %q config file: %w", imgRef.Name(), err) - } - - dirToUnpack, ok := cfgFile.Config.Labels[ConfigDirLabel] - if !ok { - return fmt.Errorf("catalog image %q is missing the required label %q", imgRef.String(), ConfigDirLabel) - } - - layers, err := img.Layers() - if err != nil { - return fmt.Errorf("error getting image layers: %w", err) - } - - dirBase := filepath.Base(dirToUnpack) - for _, layer := range layers { - layerRc, err := layer.Uncompressed() - if err != nil { - return fmt.Errorf("error getting uncompressed layer data: %w", err) - } - - // Apply the layer contents, but filter on the directory that contains catalog contents so we only cache the - // catalog contents and nothing else. This filter ensures that the files created have the proper UID and GID - // for the filesystem they will be stored on to ensure no permission errors occur when attempting to create the - // files. - _, err = archive.Apply(ctx, unpackPath, layerRc, archive.WithFilter(func(th *tar.Header) (bool, error) { - th.Uid = os.Getuid() - th.Gid = os.Getgid() - dir, file := filepath.Split(th.Name) - return (dir == "" && file == dirBase) || strings.HasPrefix(dir, fmt.Sprintf("%s/", dirBase)), nil - })) - if err != nil { - return fmt.Errorf("error applying layer to archive: %w", err) - } - } - - return nil -} diff --git a/internal/source/unpacker.go b/internal/source/unpacker.go index 7a9b90be..6115a21c 100644 --- a/internal/source/unpacker.go +++ b/internal/source/unpacker.go @@ -2,11 +2,7 @@ package source import ( "context" - "crypto/x509" - "fmt" "io/fs" - "os" - "path" catalogdv1alpha1 "github.com/operator-framework/catalogd/api/core/v1alpha1" ) @@ -76,52 +72,4 @@ const ( StateUnpacked State = "Unpacked" ) -type unpacker struct { - sources map[catalogdv1alpha1.SourceType]Unpacker -} - -// NewUnpacker returns a new composite Source that unpacks catalogs using the source -// mapping provided by the configured sources. -func NewUnpacker(sources map[catalogdv1alpha1.SourceType]Unpacker) Unpacker { - return &unpacker{sources: sources} -} - -func (s *unpacker) Unpack(ctx context.Context, catalog *catalogdv1alpha1.ClusterCatalog) (*Result, error) { - source, ok := s.sources[catalog.Spec.Source.Type] - if !ok { - return nil, fmt.Errorf("source type %q not supported", catalog.Spec.Source.Type) - } - return source.Unpack(ctx, catalog) -} - -// TODO: Generalize the cleanup logic for the Unpacker so that cleanup -// logic isn't specific to individual source types. -func (s *unpacker) Cleanup(ctx context.Context, catalog *catalogdv1alpha1.ClusterCatalog) error { - source, ok := s.sources[catalog.Spec.Source.Type] - if !ok { - return fmt.Errorf("source type %q not supported", catalog.Spec.Source.Type) - } - return source.Cleanup(ctx, catalog) -} - const UnpackCacheDir = "unpack" - -// NewDefaultUnpacker returns a new composite Source that unpacks catalogs using -// a default source mapping with built-in implementations of all of the supported -// source types. -// -// TODO: refactor NewDefaultUnpacker due to growing parameter list -func NewDefaultUnpacker(namespace, cacheDir string, certPool *x509.CertPool) (Unpacker, error) { - unpackPath := path.Join(cacheDir, UnpackCacheDir) - if err := os.MkdirAll(unpackPath, 0700); err != nil { - return nil, fmt.Errorf("creating unpack cache directory: %w", err) - } - - return NewUnpacker(map[catalogdv1alpha1.SourceType]Unpacker{ - catalogdv1alpha1.SourceTypeImage: &ImageRegistry{ - BaseCachePath: unpackPath, - AuthNamespace: namespace, - CertPool: certPool, - }, - }), nil -} diff --git a/internal/storage/localdir.go b/internal/storage/localdir.go index 04417819..93a82b71 100644 --- a/internal/storage/localdir.go +++ b/internal/storage/localdir.go @@ -34,15 +34,14 @@ func (s LocalDir) Store(ctx context.Context, catalog string, fsys fs.FS) error { return err } defer os.Remove(tempFile.Name()) - err = declcfg.WalkMetasFS(ctx, fsys, func(path string, meta *declcfg.Meta, err error) error { + if err := declcfg.WalkMetasFS(ctx, fsys, func(path string, meta *declcfg.Meta, err error) error { if err != nil { - return fmt.Errorf("error in parsing catalog content files in the filesystem: %w", err) + return err } _, err = tempFile.Write(meta.Blob) return err - }) - if err != nil { - return err + }); err != nil { + return fmt.Errorf("error walking FBC root: %w", err) } fbcFile := filepath.Join(fbcDir, "all.json") return os.Rename(tempFile.Name(), fbcFile) diff --git a/test/tools/imageregistry/imgreg.yaml b/test/tools/imageregistry/imgreg.yaml index 7d86bc2a..c8a10435 100644 --- a/test/tools/imageregistry/imgreg.yaml +++ b/test/tools/imageregistry/imgreg.yaml @@ -4,6 +4,14 @@ metadata: name: catalogd-e2e --- apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: selfsigned-issuer + namespace: catalogd-e2e +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: catalogd-e2e-registry @@ -17,8 +25,8 @@ spec: algorithm: ECDSA size: 256 issuerRef: - name: olmv1-ca - kind: ClusterIssuer + name: ${ISSUER_NAME} + kind: ${ISSUER_KIND} group: cert-manager.io --- apiVersion: apps/v1 diff --git a/test/tools/imageregistry/pre-upgrade-setup.sh b/test/tools/imageregistry/pre-upgrade-setup.sh index c1d74d1e..a3b5f356 100755 --- a/test/tools/imageregistry/pre-upgrade-setup.sh +++ b/test/tools/imageregistry/pre-upgrade-setup.sh @@ -29,7 +29,6 @@ spec: type: image image: ref: ${TEST_CLUSTER_CATALOG_IMAGE} - insecureSkipTLSVerify: true EOF kubectl wait --for=condition=Unpacked --timeout=60s ClusterCatalog $TEST_CLUSTER_CATALOG_NAME diff --git a/test/tools/imageregistry/registry.sh b/test/tools/imageregistry/registry.sh index 3bf976aa..3995c9b3 100755 --- a/test/tools/imageregistry/registry.sh +++ b/test/tools/imageregistry/registry.sh @@ -10,10 +10,19 @@ set -e # 4. Waits for kaniko pod to have Condition Complete == true, indicating the test catalog image has been built + pushed # to the test image registry # Usage: -# registry.sh +# registry.sh + +if [[ "$#" -ne 2 ]]; then + echo "Incorrect number of arguments passed" + echo "Usage: registry.sh " + exit 1 +fi + +export ISSUER_KIND=$1 +export ISSUER_NAME=$2 # create the image registry with all the certs -kubectl apply -f test/tools/imageregistry/imgreg.yaml +envsubst '${ISSUER_KIND},${ISSUER_NAME}' < test/tools/imageregistry/imgreg.yaml | kubectl apply -f - kubectl wait -n catalogd-e2e --for=condition=Available deployment/docker-registry --timeout=60s # Load the testdata onto the cluster as a configmap so it can be used with kaniko