diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 97539ab..e44f3fc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -44,7 +44,7 @@ jobs:
- name: Install Dagger
env:
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
- DAGGER_VERSION: 0.20.1
+ DAGGER_VERSION: 0.21.0
run: |
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
- name: Run CI task
diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml
index 681042f..ef8f01e 100644
--- a/.github/workflows/publish-docs.yml
+++ b/.github/workflows/publish-docs.yml
@@ -37,7 +37,7 @@ jobs:
cache-dependency-path: web/yarn.lock
- name: Setup Pages
- uses: actions/configure-pages@v5
+ uses: actions/configure-pages@v6
- name: Install dependencies
working-directory: web
@@ -48,7 +48,7 @@ jobs:
run: yarn build
- name: Upload artifact
- uses: actions/upload-pages-artifact@v4
+ uses: actions/upload-pages-artifact@v5
with:
path: web/build
@@ -64,4 +64,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v4
+ uses: actions/deploy-pages@v5
diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml
index 8d76736..92a43ed 100644
--- a/.github/workflows/release-please.yml
+++ b/.github/workflows/release-please.yml
@@ -31,7 +31,7 @@ jobs:
- name: Install Dagger
env:
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
- DAGGER_VERSION: 0.20.1
+ DAGGER_VERSION: 0.21.0
run: |
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
- name: Create image and manifest
diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml
index 30b0601..9470cc0 100644
--- a/.github/workflows/release-publish.yml
+++ b/.github/workflows/release-publish.yml
@@ -21,7 +21,7 @@ jobs:
- name: Install Dagger
env:
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
- DAGGER_VERSION: 0.20.1
+ DAGGER_VERSION: 0.21.0
run: |
curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh
- name: Create image and manifest
diff --git a/.golangci.yml b/.golangci.yml
index a4cce38..fbff241 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -16,7 +16,7 @@ linters:
- gocyclo
- goheader
- gomoddirectives
- - gomodguard
+ - gomodguard_v2
- goprintffuncname
- gosec
- govet
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 78e7f27..8032c17 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.11.0"
+ ".": "0.12.0"
}
diff --git a/.wordlist.txt b/.wordlist.txt
index 3e59b45..3df20da 100644
--- a/.wordlist.txt
+++ b/.wordlist.txt
@@ -15,6 +15,7 @@ DigitalOcean
Docusaurus
EDB
EKS
+EnterpriseDB
Enum
EnvVar
GCP
@@ -76,6 +77,7 @@ backends
barmanObjectName
barmanObjectStore
barmancloud
+benchmarked
boto
bzip
cd
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96c5627..fb5c7a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,37 @@
# Changelog
+## [0.12.0](https://github.com/cloudnative-pg/plugin-barman-cloud/compare/v0.11.0...v0.12.0) (2026-04-13)
+
+
+### Features
+
+* **deps:** Update dependency barman to v3.18.0 ([#813](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/813)) ([a8b446f](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/a8b446faa83b9381e43c324396fd1304b8a89823))
+
+
+### Bug Fixes
+
+* **deps:** Update all non-major go dependencies ([#751](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/751)) ([5001fe7](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/5001fe783130fb57a3881da3e4f534a658e3b654))
+* **deps:** Update all non-major go dependencies ([#757](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/757)) ([d031c23](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/d031c2353223796dfd182b7d6c2856855ed3011d))
+* **deps:** Update all non-major go dependencies ([#801](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/801)) ([6ae101f](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/6ae101f016b2ec5446fcb9a28a49c888f58d4232))
+* **deps:** Update dependency @easyops-cn/docusaurus-search-local to ^0.55.0 ([#753](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/753)) ([60d32cc](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/60d32cca0cebc28ddf85696ac1432c732ce7779c))
+* **deps:** Update documentation dependencies ([#833](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/833)) ([e1d4a6e](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/e1d4a6e5f7d9661311b7475676d1cedb5a152793))
+* **deps:** Update k8s.io/utils digest to 28399d8 ([#829](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/829)) ([3549e26](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/3549e2650a5ea323844944cd7ad1baf3b6fda07c))
+* **deps:** Update k8s.io/utils digest to b8788ab ([#784](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/784)) ([f64ff8e](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/f64ff8e13f203f43ae144e998be3f072cf4f3b18))
+* **deps:** Update kubernetes packages to v0.35.2 ([#788](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/788)) ([a7e28f6](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/a7e28f6cadcdd197b027a46fc209e84ee760ab0d))
+* **deps:** Update module github.com/cert-manager/cert-manager to v1.19.3 [security] ([#775](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/775)) ([79238f5](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/79238f5772cbf7e98a51a636d3661a6828c444be))
+* **deps:** Update module github.com/cert-manager/cert-manager to v1.20.2 ([#844](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/844)) ([441f43b](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/441f43be24e965d71f936d7e1750654b9f427556))
+* **deps:** Update module github.com/cloudnative-pg/api to v1.29.0 ([#837](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/837)) ([09181b0](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/09181b0bda8763241f30921f8b1d27c9c429e5ac))
+* **deps:** Update module github.com/cloudnative-pg/machinery to v0.4.0 ([#850](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/850)) ([18e3888](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/18e38887ce3fd226ba722aad586a3852ff2b0d5c))
+* **deps:** Update module google.golang.org/grpc to v1.79.3 [security] ([#819](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/819)) ([376e178](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/376e178ab5ea907aae50e6eaeb19215ec4326c53))
+* **deps:** Update module sigs.k8s.io/controller-runtime to v0.23.3 ([#789](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/789)) ([3f726ea](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/3f726ea83e996f6ead84c69bc797113e24314045))
+* **deps:** Update module sigs.k8s.io/kustomize/api to v0.21.1 ([#790](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/790)) ([84a388e](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/84a388e5d719a1b312b15b21d4ce3ac06543dbe3))
+* **metrics:** Announce sidecar injection capability ([#776](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/776)) ([4a94cb9](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/4a94cb9daef6940ad425a7e349e51444ab92379c))
+* **rbac:** Reconcile Role when ObjectStore spec changes ([#823](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/823)) ([8971a39](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/8971a397f47a0f29772189c260e71c66df019387))
+* **restore:** Race condition in parallel WAL restore spool ([#812](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/812)) ([25d72ce](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/25d72ce0a3c3d657d6d9afe1a0a98f1c6535a68a))
+* **restore:** Use custom CNPG group and version for scheme registration ([#847](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/847)) ([b1f373d](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/b1f373d84b5e24bed08f0578621c00d9cc00931f))
+* **security:** Harden GitHub Actions workflows against expression injection ([#773](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/773)) ([ce7b761](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/ce7b7612aeab6b7b4cfdccc540640829b67d7ac6))
+* Skip maintenance cycle when plugin is not enabled for backups ([#826](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/826)) ([63a67cb](https://github.com/cloudnative-pg/plugin-barman-cloud/commit/63a67cb92023998b44d1d476be5aba2e78d66e8f)), closes [#774](https://github.com/cloudnative-pg/plugin-barman-cloud/issues/774)
+
## [0.11.0](https://github.com/cloudnative-pg/plugin-barman-cloud/compare/v0.10.0...v0.11.0) (2026-01-30)
diff --git a/Taskfile.yml b/Taskfile.yml
index 35c84e1..7209506 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -6,6 +6,8 @@ output: prefixed
# Variables that are shared across tasks.
vars:
+ GO_VERSION:
+ sh: sed -n 's/^toolchain go//p' go.mod | grep . || sed -n 's/^go //p' go.mod
# renovate: datasource=docker depName=kindest/node versioning=semver
E2E_KUBERNETES_VERSION: v1.35.1
E2E_CLUSTER_NAME: barman-cloud-plugin-e2e-{{.E2E_KUBERNETES_VERSION}}
@@ -19,9 +21,9 @@ tasks:
desc: Run golangci-lint
env:
# renovate: datasource=git-refs depName=golangci-lint lookupName=https://github.com/sagikazarmark/daggerverse currentValue=main
- DAGGER_GOLANGCI_LINT_SHA: 5dcc7e4c4cd5ed230046955f42e27f2166545155
+ DAGGER_GOLANGCI_LINT_SHA: 81b688189377135bd0cf85f3ddba88c4fbb52c2d
# renovate: datasource=docker depName=golangci/golangci-lint versioning=semver
- GOLANGCI_LINT_VERSION: v2.11.2
+ GOLANGCI_LINT_VERSION: v2.12.2
cmds:
- >
GITHUB_REF= dagger -sc "github.com/sagikazarmark/daggerverse/golangci-lint@${DAGGER_GOLANGCI_LINT_SHA}
@@ -44,7 +46,7 @@ tasks:
- wordlist-ordered
env:
# renovate: datasource=git-refs depName=spellcheck lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
- DAGGER_SPELLCHECK_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
+ DAGGER_SPELLCHECK_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/spellcheck@${DAGGER_SPELLCHECK_SHA}
@@ -58,7 +60,7 @@ tasks:
desc: Check for conventional commits
env:
# renovate: datasource=git-refs depName=commitlint lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
- DAGGER_COMMITLINT_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
+ DAGGER_COMMITLINT_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/commitlint@${DAGGER_COMMITLINT_SHA}
@@ -72,7 +74,7 @@ tasks:
- wordlist-ordered
env:
# renovate: datasource=git-refs depName=uncommitted lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
- DAGGER_UNCOMMITTED_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
+ DAGGER_UNCOMMITTED_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
cmds:
- GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/uncommitted@${DAGGER_UNCOMMITTED_SHA} check-uncommitted --source . stdout
sources:
@@ -84,7 +86,7 @@ tasks:
- controller-gen
env:
# renovate: datasource=git-refs depName=crd-gen-refs lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
- DAGGER_CRDGENREF_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
+ DAGGER_CRDGENREF_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
# renovate: datasource=go depName=github.com/elastic/crd-ref-docs
CRDREFDOCS_VERSION: v0.3.0
cmds:
@@ -128,16 +130,14 @@ tasks:
go-test:
desc: Run go test
env:
- # renovate: datasource=docker depName=golang versioning=semver
- GOLANG_IMAGE_VERSION: 1.26.1
# renovate: datasource=git-refs depname=kubernetes packageName=https://github.com/kubernetes/kubernetes versioning=semver
K8S_VERSION: 1.31.0
# renovate: datasource=git-refs depName=controller-runtime packageName=https://github.com/kubernetes-sigs/controller-runtime versioning=semver
- SETUP_ENVTEST_VERSION: 0.23.3
+ SETUP_ENVTEST_VERSION: 0.24.1
cmds:
- >
GITHUB_REF= dagger -s call -m ./dagger/gotest
- --go-version ${GOLANG_IMAGE_VERSION}
+ --go-version {{.GO_VERSION}}
--kube-version ${K8S_VERSION}
--setup-envtest-version ${SETUP_ENVTEST_VERSION}
unit-test --src .
@@ -206,7 +206,7 @@ tasks:
- start-build-network
vars:
# renovate: datasource=github-tags depName=dagger/dagger versioning=semver
- DAGGER_VERSION: 0.20.1
+ DAGGER_VERSION: 0.21.0
DAGGER_ENGINE_IMAGE: registry.dagger.io/engine:v{{ .DAGGER_VERSION }}
cmds:
- >
@@ -231,7 +231,7 @@ tasks:
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
- build --dir . --file containers/Dockerfile.plugin --platform linux/amd64
+ build --dir . --file containers/Dockerfile.plugin --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64
publish --ref {{ .REGISTRY_NAME }}:{{ .REGISTRY_PORT }}/plugin-barman-cloud --tags testing
# We build an image and push it to a local registry.
@@ -248,7 +248,7 @@ tasks:
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
- build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64
+ build --dir . --file containers/Dockerfile.sidecar --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64
publish --ref {{ .REGISTRY_NAME }}:{{ .REGISTRY_PORT }}/sidecar-barman-cloud --tags testing
build-images:
@@ -305,8 +305,6 @@ tasks:
- build-images
- start-kind-cluster
vars:
- # renovate: datasource=docker depName=golang versioning=semver
- GOLANG_IMAGE_VERSION: 1.26.1
KUBECONFIG_PATH:
sh: mktemp -t kubeconfig-XXXXX
env:
@@ -317,15 +315,12 @@ tasks:
GITHUB_REF= dagger call -m dagger/e2e/ run
--source .
--kubeconfig {{.KUBECONFIG_PATH}}
- --go-version {{ .GOLANG_IMAGE_VERSION }}
+ --go-version {{.GO_VERSION}}
e2e-ephemeral:
desc: Run e2e tests in an ephemeral k3s cluster
deps:
- build-images
- vars:
- # renovate: datasource=docker depName=golang versioning=semver
- GOLANG_IMAGE_VERSION: 1.26.1
env:
_EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{ .DAGGER_ENGINE_CONTAINER_NAME }}
cmds:
@@ -334,7 +329,7 @@ tasks:
--source .
--ca certs/ca.pem
--registry {{.REGISTRY_NAME}}:{{.REGISTRY_PORT}}
- --go-version {{ .GOLANG_IMAGE_VERSION }}
+ --go-version {{.GO_VERSION}}
ci:
desc: Run the CI pipeline
@@ -373,12 +368,12 @@ tasks:
- >
dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
--registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD
- build --dir . --file containers/Dockerfile.plugin --platform linux/amd64 --platform linux/arm64
+ build --dir . --file containers/Dockerfile.plugin --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64 --platform linux/arm64
publish --ref {{.PLUGIN_IMAGE_NAME}} --tags {{.IMAGE_VERSION}}
- >
dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
--registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD
- build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64 --platform linux/arm64
+ build --dir . --file containers/Dockerfile.sidecar --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64 --platform linux/arm64
publish --ref {{.SIDECAR_IMAGE_NAME}} --tags {{.IMAGE_VERSION}}
controller-gen:
@@ -386,7 +381,7 @@ tasks:
run: once
env:
# renovate: datasource=git-refs depName=controller-gen lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
- DAGGER_CONTROLLER_GEN_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
+ DAGGER_CONTROLLER_GEN_SHA: 21755df1a27febff19b28dbe6ae57116f6088bb0
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/controller-gen@${DAGGER_CONTROLLER_GEN_SHA}
@@ -458,7 +453,7 @@ tasks:
IMAGE_VERSION: '{{regexReplaceAll "(\\d+)/merge" .GITHUB_REF_NAME "pr-${1}"}}'
env:
# renovate: datasource=git-refs depName=kustomize lookupName=https://github.com/sagikazarmark/daggerverse currentValue=main
- DAGGER_KUSTOMIZE_SHA: 5dcc7e4c4cd5ed230046955f42e27f2166545155
+ DAGGER_KUSTOMIZE_SHA: 81b688189377135bd0cf85f3ddba88c4fbb52c2d
cmds:
- >
dagger -s call -m https://github.com/sagikazarmark/daggerverse/kustomize@${DAGGER_KUSTOMIZE_SHA}
@@ -488,7 +483,7 @@ tasks:
- GITHUB_TOKEN
env:
# renovate: datasource=git-refs depName=gh lookupName=https://github.com/sagikazarmark/daggerverse
- DAGGER_GH_SHA: 5dcc7e4c4cd5ed230046955f42e27f2166545155
+ DAGGER_GH_SHA: 81b688189377135bd0cf85f3ddba88c4fbb52c2d
preconditions:
- sh: "[[ {{.GITHUB_REF}} =~ 'refs/tags/v.*' ]]"
msg: not a tag, failing
diff --git a/api/v1/groupversion_info.go b/api/v1/groupversion_info.go
index d0e2f09..bc99ba2 100644
--- a/api/v1/groupversion_info.go
+++ b/api/v1/groupversion_info.go
@@ -20,17 +20,19 @@ SPDX-License-Identifier: Apache-2.0
package v1
import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
- "sigs.k8s.io/controller-runtime/pkg/scheme"
)
-var (
- // GroupVersion is group version used to register these objects.
- GroupVersion = schema.GroupVersion{Group: "barmancloud.cnpg.io", Version: "v1"}
+// GroupVersion is group version used to register these objects.
+var GroupVersion = schema.GroupVersion{Group: "barmancloud.cnpg.io", Version: "v1"}
- // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
- SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+// AddKnownTypes add to the passed schema the Kubernetes types
+// exposed by this package.
+func AddKnownTypes(scheme *runtime.Scheme) {
+ scheme.AddKnownTypes(GroupVersion,
+ &ObjectStore{}, &ObjectStoreList{})
- // AddToScheme adds the types in this group-version to the given scheme.
- AddToScheme = SchemeBuilder.AddToScheme
-)
+ metav1.AddToGroupVersion(scheme, GroupVersion)
+}
diff --git a/api/v1/objectstore_types.go b/api/v1/objectstore_types.go
index f179af9..928d52c 100644
--- a/api/v1/objectstore_types.go
+++ b/api/v1/objectstore_types.go
@@ -124,7 +124,3 @@ type ObjectStoreList struct {
metav1.ListMeta `json:"metadata,omitempty"`
Items []ObjectStore `json:"items"`
}
-
-func init() {
- SchemeBuilder.Register(&ObjectStore{}, &ObjectStoreList{})
-}
diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go
index 05f7e61..09f115f 100644
--- a/api/v1/zz_generated.deepcopy.go
+++ b/api/v1/zz_generated.deepcopy.go
@@ -25,7 +25,7 @@ package v1
import (
corev1 "k8s.io/api/core/v1"
- runtime "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
diff --git a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml
index 43c675d..f8688ce 100644
--- a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml
+++ b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
+ controller-gen.kubebuilder.io/version: v0.21.0
name: objectstores.barmancloud.cnpg.io
spec:
group: barmancloud.cnpg.io
@@ -144,10 +144,11 @@ spec:
description: |-
Compress a backup file (a tar file per tablespace) while streaming it
to the object store. Available options are empty string (no
- compression, default), `gzip`, `bzip2`, and `snappy`.
+ compression, default), `gzip`, `bzip2`, `lz4`, and `snappy`.
enum:
- bzip2
- gzip
+ - lz4
- snappy
type: string
encryption:
diff --git a/containers/Dockerfile.plugin b/containers/Dockerfile.plugin
index 61fe420..804ee22 100644
--- a/containers/Dockerfile.plugin
+++ b/containers/Dockerfile.plugin
@@ -1,5 +1,7 @@
# Build the manager binary
-FROM --platform=$BUILDPLATFORM golang:1.26.1 AS gobuilder
+# GO_VERSION must be passed as a build arg (read from go.mod by Taskfile)
+ARG GO_VERSION
+FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} AS gobuilder
ARG TARGETOS
ARG TARGETARCH
diff --git a/containers/Dockerfile.sidecar b/containers/Dockerfile.sidecar
index 13c1cee..3970bba 100644
--- a/containers/Dockerfile.sidecar
+++ b/containers/Dockerfile.sidecar
@@ -5,7 +5,9 @@
# Both components are built before going into a distroless container
# Build the manager binary
-FROM --platform=$BUILDPLATFORM golang:1.26.1 AS gobuilder
+# GO_VERSION must be passed as a build arg (read from go.mod by Taskfile)
+ARG GO_VERSION
+FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} AS gobuilder
ARG TARGETOS
ARG TARGETARCH
diff --git a/containers/sidecar-requirements.in b/containers/sidecar-requirements.in
index bc51cde..667c547 100644
--- a/containers/sidecar-requirements.in
+++ b/containers/sidecar-requirements.in
@@ -1,3 +1,3 @@
-barman[azure,cloud,google,snappy,zstandard,lz4]==3.17.0
+barman[azure,cloud,google,snappy,zstandard,lz4]==3.19.1
setuptools==82.0.1
zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
diff --git a/containers/sidecar-requirements.txt b/containers/sidecar-requirements.txt
index 05243bb..379ab90 100644
--- a/containers/sidecar-requirements.txt
+++ b/containers/sidecar-requirements.txt
@@ -4,37 +4,37 @@
#
# pip-compile --allow-unsafe --generate-hashes --output-file=sidecar-requirements.txt --strip-extras sidecar-requirements.in
#
-azure-core==1.38.2 \
- --hash=sha256:074806c75cf239ea284a33a66827695ef7aeddac0b4e19dda266a93e4665ead9 \
- --hash=sha256:67562857cb979217e48dc60980243b61ea115b77326fa93d83b729e7ff0482e7
+azure-core==1.41.0 \
+ --hash=sha256:522b4011e8180b1a3dcd2024396a4e7fe9ac37fb8597db47163d230b5efe892d \
+ --hash=sha256:f46ff5dfcd230f25cf1c19e8a34b8dc08a337b2503e268bb600a16c00db8ad5a
# via
# azure-identity
# azure-storage-blob
-azure-identity==1.25.2 \
- --hash=sha256:030dbaa720266c796221c6cdbd1999b408c079032c919fef725fcc348a540fe9 \
- --hash=sha256:1b40060553d01a72ba0d708b9a46d0f61f56312e215d8896d836653ffdc6753d
+azure-identity==1.25.3 \
+ --hash=sha256:ab23c0d63015f50b630ef6c6cf395e7262f439ce06e5d07a64e874c724f8d9e6 \
+ --hash=sha256:f4d0b956a8146f30333e071374171f3cfa7bdb8073adb8c3814b65567aa7447c
# via barman
-azure-storage-blob==12.28.0 \
- --hash=sha256:00fb1db28bf6a7b7ecaa48e3b1d5c83bfadacc5a678b77826081304bd87d6461 \
- --hash=sha256:e7d98ea108258d29aa0efbfd591b2e2075fa1722a2fae8699f0b3c9de11eff41
+azure-storage-blob==12.29.0 \
+ --hash=sha256:2824ddd7ebc9056034ebc76b17971a38e9aa5835abb0d565b9700493f2a6c657 \
+ --hash=sha256:ccf8a1bcd5e49df83ab85aab793b579e5ba2eeea2ad8900b2f62ca3a37dc391f
# via barman
-barman==3.17.0 \
- --hash=sha256:07b033da14e72f103de44261c31bd0c3169bbb2e4de3481c6bb3510e9870d38e \
- --hash=sha256:d6618990a6dbb31af3286d746a278a038534b7e3cc617c2b379ef7ebdeb7ed5a
+barman==3.19.1 \
+ --hash=sha256:0a6a9e1babf97687732d8b2a3eb79ea95d55246a5257b9433865cb6e755221c0 \
+ --hash=sha256:2f71c4a1f1ba53f694cbdf838bb9906d8ba02b97d1fd3041196e8999bec7a1ee
# via -r sidecar-requirements.in
-boto3==1.42.63 \
- --hash=sha256:cd008cfd0d7ea30f1c5e22daf0998c55b7c6c68cb68eea05110e33fe641173d5 \
- --hash=sha256:d502a89a0acc701692ae020d15981f2a82e9eb3485acc651cfd0cf1a3afe79ee
+boto3==1.43.14 \
+ --hash=sha256:574335744656cfed0b362a0a0467aaf2eb2bf15526edcd02d31d3c661f4b09e4 \
+ --hash=sha256:5c0a994b3182061ee101812e721100717a4d664f9f4ceaf4a86b6d032ce9fc2d
# via barman
-botocore==1.42.63 \
- --hash=sha256:1fdfc33cff58d21e8622cf620ba2bba3cff324557932aaf935b5374e4610f059 \
- --hash=sha256:83f39d04f2b316bdfc59a3cac2d12238bde7126ac99d9a57d910dbd86d58c528
+botocore==1.43.14 \
+ --hash=sha256:1f4a2a95ea78c10398e78431e98c1fe47adb54a7b10a32975144c1f541186658 \
+ --hash=sha256:b9e500737e43d2f147c9d4e23b54360335e77d4c0ba90a318f51b65e06cb8516
# via
# boto3
# s3transfer
-certifi==2026.2.25 \
- --hash=sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa \
- --hash=sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7
+certifi==2026.5.20 \
+ --hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
+ --hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
# via requests
cffi==2.0.0 \
--hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \
@@ -122,120 +122,136 @@ cffi==2.0.0 \
--hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \
--hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf
# via cryptography
-charset-normalizer==3.4.5 \
- --hash=sha256:014837af6fabf57121b6254fa8ade10dceabc3528b27b721a64bbc7b8b1d4eb4 \
- --hash=sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66 \
- --hash=sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54 \
- --hash=sha256:02a9d1b01c1e12c27883b0c9349e0bcd9ae92e727ff1a277207e1a262b1cbf05 \
- --hash=sha256:036c079aa08a6a592b82487f97c60b439428320ed1b2ea0b3912e99d30c77765 \
- --hash=sha256:039215608ac7b358c4da0191d10fc76868567fbf276d54c14721bdedeb6de064 \
- --hash=sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819 \
- --hash=sha256:0a45e504f5e1be0bd385935a8e1507c442349ca36f511a47057a71c9d1d6ea9e \
- --hash=sha256:0b362bcd27819f9c07cbf23db4e0e8cd4b44c5ecd900c2ff907b2b92274a7412 \
- --hash=sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc \
- --hash=sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e \
- --hash=sha256:10b473fc8dca1c3ad8559985794815f06ca3fc71942c969129070f2c3cdf7281 \
- --hash=sha256:131716d6786ad5e3dc542f5cc6f397ba3339dc0fb87f87ac30e550e8987756af \
- --hash=sha256:14498a429321de554b140013142abe7608f9d8ccc04d7baf2ad60498374aefa2 \
- --hash=sha256:149ec69866c3d6c2fb6f758dbc014ecb09f30b35a5ca90b6a8a2d4e54e18fdfe \
- --hash=sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8 \
- --hash=sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262 \
- --hash=sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac \
- --hash=sha256:1a374cc0b88aa710e8865dc1bd6edb3743c59f27830f0293ab101e4cf3ce9f85 \
- --hash=sha256:1d1401945cb77787dbd3af2446ff2d75912327c4c3a1526ab7955ecf8600687c \
- --hash=sha256:1f2da5cbb9becfcd607757a169e38fb82aa5fd86fae6653dea716e7b613fe2cf \
- --hash=sha256:259cd1ca995ad525f638e131dbcc2353a586564c038fc548a3fe450a91882139 \
- --hash=sha256:2820a98460c83663dd8ec015d9ddfd1e4879f12e06bb7d0500f044fb477d2770 \
- --hash=sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d \
- --hash=sha256:2b970382e4a36bed897c19f310f31d7d13489c11b4f468ddfba42d41cddfb918 \
- --hash=sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3 \
- --hash=sha256:30987f4a8ed169983f93e1be8ffeea5214a779e27ed0b059835c7afe96550ad7 \
- --hash=sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39 \
- --hash=sha256:340810d34ef83af92148e96e3e44cb2d3f910d2bf95e5618a5c467d9f102231d \
- --hash=sha256:3f64c6bf8f32f9133b668c7f7a7cbdbc453412bc95ecdbd157f3b1e377a92990 \
- --hash=sha256:4167a621a9a1a986c73777dbc15d4b5eac8ac5c10393374109a343d4013ec765 \
- --hash=sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1 \
- --hash=sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa \
- --hash=sha256:4b8551b6e6531e156db71193771c93bda78ffc4d1e6372517fe58ad3b91e4659 \
- --hash=sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d \
- --hash=sha256:50bcbca6603c06a1dcc7b056ed45c37715fb5d2768feb3bcd37d2313c587a5b9 \
- --hash=sha256:530beedcec9b6e027e7a4b6ce26eed36678aa39e17da85e6e03d7bd9e8e9d7c9 \
- --hash=sha256:568e3c34b58422075a1b49575a6abc616d9751b4d61b23f712e12ebb78fe47b2 \
- --hash=sha256:573ef5814c4b7c0d59a7710aa920eaaaef383bd71626aa420fba27b5cab92e8d \
- --hash=sha256:58ad8270cfa5d4bef1bc85bd387217e14ff154d6630e976c6f56f9a040757475 \
- --hash=sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c \
- --hash=sha256:5bcb3227c3d9aaf73eaaab1db7ccd80a8995c509ee9941e2aae060ca6e4e5d81 \
- --hash=sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67 \
- --hash=sha256:5fea359734b140d0d6741189fea5478c6091b54ffc69d7ce119e0a05637d8c99 \
- --hash=sha256:60d68e820af339df4ae8358c7a2e7596badeb61e544438e489035f9fbf3246a5 \
- --hash=sha256:610f72c0ee565dfb8ae1241b666119582fdbfe7c0975c175be719f940e110694 \
- --hash=sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf \
- --hash=sha256:65b3c403a5b6b8034b655e7385de4f72b7b244869a22b32d4030b99a60593eca \
- --hash=sha256:66dee73039277eb35380d1b82cccc69cc82b13a66f9f4a18da32d573acf02b7c \
- --hash=sha256:708c7acde173eedd4bfa4028484426ba689d2103b28588c513b9db2cd5ecde9c \
- --hash=sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636 \
- --hash=sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f \
- --hash=sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02 \
- --hash=sha256:75ee9c1cce2911581a70a3c0919d8bccf5b1cbc9b0e5171400ec736b4b569497 \
- --hash=sha256:76a9d0de4d0eab387822e7b35d8f89367dd237c72e82ab42b9f7bf5e15ada00f \
- --hash=sha256:77be992288f720306ab4108fe5c74797de327f3248368dfc7e1a916d6ed9e5a2 \
- --hash=sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d \
- --hash=sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873 \
- --hash=sha256:82cc7c2ad42faec8b574351f8bc2a0c049043893853317bd9bb309f5aba6cb5a \
- --hash=sha256:8a28afb04baa55abf26df544e3e5c6534245d3daa5178bc4a8eeb48202060d0e \
- --hash=sha256:8b78d8a609a4b82c273257ee9d631ded7fac0d875bdcdccc109f3ee8328cfcb1 \
- --hash=sha256:8ce11cd4d62d11166f2b441e30ace226c19a3899a7cf0796f668fba49a9fb123 \
- --hash=sha256:8fff79bf5978c693c9b1a4d71e4a94fddfb5fe744eb062a318e15f4a2f63a550 \
- --hash=sha256:92263f7eca2f4af326cd20de8d16728d2602f7cfea02e790dcde9d83c365d7cc \
- --hash=sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36 \
- --hash=sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644 \
- --hash=sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4 \
- --hash=sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0 \
- --hash=sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e \
- --hash=sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f \
- --hash=sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4 \
- --hash=sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98 \
- --hash=sha256:aa2f963b4da26daf46231d9b9e0e2c9408a751f8f0d0f44d2de56d3caf51d294 \
- --hash=sha256:aa92ec1102eaff840ccd1021478af176a831f1bccb08e526ce844b7ddda85c22 \
- --hash=sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23 \
- --hash=sha256:ae8b03427410731469c4033934cf473426faff3e04b69d2dfb64a4281a3719f8 \
- --hash=sha256:afca7f78067dd27c2b848f1b234623d26b87529296c6c5652168cc1954f2f3b2 \
- --hash=sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362 \
- --hash=sha256:b3e71afc578b98512bfe7bdb822dd6bc57d4b0093b4b6e5487c1e96ad4ace242 \
- --hash=sha256:ba20bdf69bd127f66d0174d6f2a93e69045e0b4036dc1ca78e091bcc765830c4 \
- --hash=sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95 \
- --hash=sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d \
- --hash=sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94 \
- --hash=sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6 \
- --hash=sha256:c7e84e0c0005e3bdc1a9211cd4e62c78ba80bc37b2365ef4410cd2007a9047f2 \
- --hash=sha256:cace89841c0599d736d3d74a27bc5821288bb47c5441923277afc6059d7fbcb4 \
- --hash=sha256:cd2d0f0ec9aa977a27731a3209ebbcacebebaf41f902bd453a928bfd281cf7f8 \
- --hash=sha256:d01de5e768328646e6a3fa9e562706f8f6641708c115c62588aef2b941a4f88e \
- --hash=sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a \
- --hash=sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce \
- --hash=sha256:d29dd9c016f2078b43d0c357511e87eee5b05108f3dd603423cb389b89813969 \
- --hash=sha256:d31f0d1671e1534e395f9eb84a68e0fb670e1edb1fe819a9d7f564ae3bc4e53f \
- --hash=sha256:d4eb8ac7469b2a5d64b5b8c04f84d8bf3ad340f4514b98523805cbf46e3b3923 \
- --hash=sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6 \
- --hash=sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee \
- --hash=sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6 \
- --hash=sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467 \
- --hash=sha256:e09f671a54ce70b79a1fc1dc6da3072b7ef7251fadb894ed92d9aa8218465a5f \
- --hash=sha256:e22d1059b951e7ae7c20ef6b06afd10fb95e3c41bf3c4fbc874dba113321c193 \
- --hash=sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7 \
- --hash=sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9 \
- --hash=sha256:e545b51da9f9af5c67815ca0eb40676c0f016d0b0381c86f20451e35696c5f95 \
- --hash=sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763 \
- --hash=sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7 \
- --hash=sha256:ec56a2266f32bc06ed3c3e2a8f58417ce02f7e0356edc89786e52db13c593c98 \
- --hash=sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60 \
- --hash=sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade \
- --hash=sha256:ed98364e1c262cf5f9363c3eca8c2df37024f52a8fa1180a3610014f26eac51c \
- --hash=sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2 \
- --hash=sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f \
- --hash=sha256:f8102ae93c0bc863b1d41ea0f4499c20a83229f52ed870850892df555187154a \
- --hash=sha256:fc1c64934b8faf7584924143eb9db4770bbdb16659626e1a1a4d9efbcb68d947 \
- --hash=sha256:ff95a9283de8a457e6b12989de3f9f5193430f375d64297d323a615ea52cbdb3
+charset-normalizer==3.4.7 \
+ --hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \
+ --hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \
+ --hash=sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67 \
+ --hash=sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4 \
+ --hash=sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0 \
+ --hash=sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c \
+ --hash=sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5 \
+ --hash=sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444 \
+ --hash=sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153 \
+ --hash=sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9 \
+ --hash=sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01 \
+ --hash=sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217 \
+ --hash=sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b \
+ --hash=sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c \
+ --hash=sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a \
+ --hash=sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83 \
+ --hash=sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5 \
+ --hash=sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7 \
+ --hash=sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb \
+ --hash=sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c \
+ --hash=sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1 \
+ --hash=sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42 \
+ --hash=sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab \
+ --hash=sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df \
+ --hash=sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e \
+ --hash=sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207 \
+ --hash=sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18 \
+ --hash=sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734 \
+ --hash=sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38 \
+ --hash=sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110 \
+ --hash=sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18 \
+ --hash=sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44 \
+ --hash=sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d \
+ --hash=sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48 \
+ --hash=sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e \
+ --hash=sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5 \
+ --hash=sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d \
+ --hash=sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53 \
+ --hash=sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790 \
+ --hash=sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c \
+ --hash=sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b \
+ --hash=sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116 \
+ --hash=sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d \
+ --hash=sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10 \
+ --hash=sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6 \
+ --hash=sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2 \
+ --hash=sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776 \
+ --hash=sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a \
+ --hash=sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265 \
+ --hash=sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008 \
+ --hash=sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943 \
+ --hash=sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374 \
+ --hash=sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246 \
+ --hash=sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e \
+ --hash=sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5 \
+ --hash=sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616 \
+ --hash=sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15 \
+ --hash=sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41 \
+ --hash=sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960 \
+ --hash=sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752 \
+ --hash=sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e \
+ --hash=sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72 \
+ --hash=sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7 \
+ --hash=sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8 \
+ --hash=sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b \
+ --hash=sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4 \
+ --hash=sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545 \
+ --hash=sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706 \
+ --hash=sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366 \
+ --hash=sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb \
+ --hash=sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a \
+ --hash=sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e \
+ --hash=sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00 \
+ --hash=sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f \
+ --hash=sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a \
+ --hash=sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1 \
+ --hash=sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66 \
+ --hash=sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356 \
+ --hash=sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319 \
+ --hash=sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4 \
+ --hash=sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad \
+ --hash=sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d \
+ --hash=sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5 \
+ --hash=sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7 \
+ --hash=sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0 \
+ --hash=sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686 \
+ --hash=sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34 \
+ --hash=sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49 \
+ --hash=sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c \
+ --hash=sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1 \
+ --hash=sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e \
+ --hash=sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60 \
+ --hash=sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0 \
+ --hash=sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274 \
+ --hash=sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d \
+ --hash=sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0 \
+ --hash=sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae \
+ --hash=sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f \
+ --hash=sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d \
+ --hash=sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe \
+ --hash=sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3 \
+ --hash=sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393 \
+ --hash=sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1 \
+ --hash=sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af \
+ --hash=sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44 \
+ --hash=sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00 \
+ --hash=sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c \
+ --hash=sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3 \
+ --hash=sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7 \
+ --hash=sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd \
+ --hash=sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e \
+ --hash=sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b \
+ --hash=sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8 \
+ --hash=sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259 \
+ --hash=sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859 \
+ --hash=sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46 \
+ --hash=sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30 \
+ --hash=sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b \
+ --hash=sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46 \
+ --hash=sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24 \
+ --hash=sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a \
+ --hash=sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24 \
+ --hash=sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc \
+ --hash=sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215 \
+ --hash=sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063 \
+ --hash=sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832 \
+ --hash=sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6 \
+ --hash=sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79 \
+ --hash=sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464
# via requests
cramjam==2.11.0 \
--hash=sha256:028400d699442d40dbda02f74158c73d05cb76587a12490d0bfedd958fd49188 \
@@ -374,82 +390,82 @@ cramjam==2.11.0 \
# via
# barman
# python-snappy
-cryptography==46.0.5 \
- --hash=sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72 \
- --hash=sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235 \
- --hash=sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9 \
- --hash=sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356 \
- --hash=sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257 \
- --hash=sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad \
- --hash=sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4 \
- --hash=sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c \
- --hash=sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614 \
- --hash=sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed \
- --hash=sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31 \
- --hash=sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229 \
- --hash=sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0 \
- --hash=sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731 \
- --hash=sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b \
- --hash=sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4 \
- --hash=sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4 \
- --hash=sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263 \
- --hash=sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595 \
- --hash=sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1 \
- --hash=sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678 \
- --hash=sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48 \
- --hash=sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76 \
- --hash=sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0 \
- --hash=sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18 \
- --hash=sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d \
- --hash=sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d \
- --hash=sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1 \
- --hash=sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981 \
- --hash=sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7 \
- --hash=sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82 \
- --hash=sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2 \
- --hash=sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4 \
- --hash=sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663 \
- --hash=sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c \
- --hash=sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d \
- --hash=sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a \
- --hash=sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a \
- --hash=sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d \
- --hash=sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b \
- --hash=sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a \
- --hash=sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826 \
- --hash=sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee \
- --hash=sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9 \
- --hash=sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648 \
- --hash=sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da \
- --hash=sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2 \
- --hash=sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2 \
- --hash=sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87
+cryptography==48.0.0 \
+ --hash=sha256:0890f502ddf7d9c6426129c3f49f5c0a39278ed7cd6322c8755ffca6ee675a13 \
+ --hash=sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6 \
+ --hash=sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8 \
+ --hash=sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25 \
+ --hash=sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c \
+ --hash=sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832 \
+ --hash=sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12 \
+ --hash=sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c \
+ --hash=sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7 \
+ --hash=sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c \
+ --hash=sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec \
+ --hash=sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5 \
+ --hash=sha256:4defde8685ae324a9eb9d818717e93b4638ef67070ac9bc15b8ca85f63048355 \
+ --hash=sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c \
+ --hash=sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741 \
+ --hash=sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86 \
+ --hash=sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321 \
+ --hash=sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a \
+ --hash=sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7 \
+ --hash=sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920 \
+ --hash=sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e \
+ --hash=sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff \
+ --hash=sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd \
+ --hash=sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3 \
+ --hash=sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f \
+ --hash=sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602 \
+ --hash=sha256:84cf79f0dc8b36ac5da873481716e87aef31fcfa0444f9e1d8b4b2cece142855 \
+ --hash=sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18 \
+ --hash=sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a \
+ --hash=sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336 \
+ --hash=sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239 \
+ --hash=sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74 \
+ --hash=sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a \
+ --hash=sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c \
+ --hash=sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4 \
+ --hash=sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c \
+ --hash=sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f \
+ --hash=sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4 \
+ --hash=sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db \
+ --hash=sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166 \
+ --hash=sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5 \
+ --hash=sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f \
+ --hash=sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae \
+ --hash=sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20 \
+ --hash=sha256:db63bf618e5dea46c07de12e900fe1cdd2541e6dc9dbae772a70b7d4d4765f6a \
+ --hash=sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057 \
+ --hash=sha256:ecde28a596bead48b0cfd2a1b4416c3d43074c2d785e3a398d7ec1fc4d0f7fbb \
+ --hash=sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c \
+ --hash=sha256:fdfef35d751d510fcef5252703621574364fec16418c4a1e5e1055248401054b
# via
# azure-identity
# azure-storage-blob
# google-auth
# msal
# pyjwt
-google-api-core==2.30.0 \
- --hash=sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b \
- --hash=sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5
+google-api-core==2.30.3 \
+ --hash=sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8 \
+ --hash=sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b
# via
# google-cloud-core
# google-cloud-storage
-google-auth==2.49.0 \
- --hash=sha256:9cc2d9259d3700d7a257681f81052db6737495a1a46b610597f4b8bafe5286ae \
- --hash=sha256:f893ef7307f19cf53700b7e2f61b5a6affe3aa0edf9943b13788920ab92d8d87
+google-auth==2.53.0 \
+ --hash=sha256:6e7449917c599b35126a99ec268ec6880301f2fea41dce198fe8fd83ff642b68 \
+ --hash=sha256:e7e6aa16f6bee7b2b264830fd04f08087a1d5a836df516251a5d15327b246c9c
# via
# google-api-core
# google-cloud-core
# google-cloud-storage
-google-cloud-core==2.5.0 \
- --hash=sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc \
- --hash=sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963
+google-cloud-core==2.6.0 \
+ --hash=sha256:6d63ac8e5eca6d9e4319d0a1e2265fadcd7f1049904378caecfa01cf52dd869e \
+ --hash=sha256:e76149739f90fac1fc6757c09f47eaccb3145b54adbd7759b0f7c4b235f46c83
# via google-cloud-storage
-google-cloud-storage==3.9.0 \
- --hash=sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066 \
- --hash=sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc
+google-cloud-storage==3.10.1 \
+ --hash=sha256:97db9aa4460727982040edd2bd13ff3d5e2260b5331ad22895802da1fc2a5286 \
+ --hash=sha256:a72f656759b7b99bda700f901adcb3425a828d4a29f911bc26b3ea79c5b1217f
# via barman
google-crc32c==1.8.0 \
--hash=sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8 \
@@ -488,17 +504,17 @@ google-crc32c==1.8.0 \
# via
# google-cloud-storage
# google-resumable-media
-google-resumable-media==2.8.0 \
- --hash=sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582 \
- --hash=sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae
+google-resumable-media==2.9.0 \
+ --hash=sha256:c8901e88e389af8bed64d9696c74d8bad961865eb2236e13e0bfca9bb0a65ca3 \
+ --hash=sha256:f7cfb224846a9dd444d125115dfbe8ef02a2b893e78f087762fe716a255a734b
# via google-cloud-storage
-googleapis-common-protos==1.73.0 \
- --hash=sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a \
- --hash=sha256:dfdaaa2e860f242046be561e6d6cb5c5f1541ae02cfbcb034371aadb2942b4e8
+googleapis-common-protos==1.75.0 \
+ --hash=sha256:53a062ff3c32552fbd62c11fe23768b78e4ddf0494d5e5fd97d3f4689c75fbbd \
+ --hash=sha256:961ed60399c457ceb0ee8f285a84c870aabc9c6a832b9d37bb281b5bebde43ed
# via google-api-core
-idna==3.11 \
- --hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
- --hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902
+idna==3.16 \
+ --hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
+ --hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
# via requests
isodate==0.7.2 \
--hash=sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15 \
@@ -569,9 +585,9 @@ lz4==4.4.5 \
--hash=sha256:f9b8bde9909a010c75b3aea58ec3910393b758f3c219beed67063693df854db0 \
--hash=sha256:ff1b50aeeec64df5603f17984e4b5be6166058dcf8f1e26a3da40d7a0f6ab547
# via barman
-msal==1.35.1 \
- --hash=sha256:70cac18ab80a053bff86219ba64cfe3da1f307c74b009e2da57ef040eb1b5656 \
- --hash=sha256:8f4e82f34b10c19e326ec69f44dc6b30171f2f7098f3720ea8a9f0c11832caa3
+msal==1.36.0 \
+ --hash=sha256:36ecac30e2ff4322d956029aabce3c82301c29f0acb1ad89b94edcabb0e58ec4 \
+ --hash=sha256:3f6a4af2b036b476a4215111c4297b4e6e236ed186cd804faefba23e4990978b
# via
# azure-identity
# msal-extensions
@@ -579,40 +595,36 @@ msal-extensions==1.3.1 \
--hash=sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca \
--hash=sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4
# via azure-identity
-proto-plus==1.27.1 \
- --hash=sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147 \
- --hash=sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc
+proto-plus==1.28.0 \
+ --hash=sha256:38e5696342835b08fc116f30a25665b29531cda9d5d5643e9b81fc312385abd9 \
+ --hash=sha256:a630604310899e73c59ec302e5765c058d412b2f090b9c79c8822589f14955b8
# via google-api-core
-protobuf==6.33.5 \
- --hash=sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c \
- --hash=sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02 \
- --hash=sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c \
- --hash=sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd \
- --hash=sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a \
- --hash=sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190 \
- --hash=sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c \
- --hash=sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5 \
- --hash=sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0 \
- --hash=sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b
+protobuf==7.35.0 \
+ --hash=sha256:4c4617b83ade0e279d1d2bfe04025a1adb87f9ed657de038620dc0ff959357f6 \
+ --hash=sha256:4cbf5cc286130e06a6c9bbefac442431173906dfcc979712183d4adcc01b37ee \
+ --hash=sha256:66be6c513931c794fa92c080ffee41671390da3d79da219cf9c0c0907f035dda \
+ --hash=sha256:6c0f98f10c8a05ea30f8993dfef2de093d27b490fdae78bb60c8343795d55011 \
+ --hash=sha256:a2efd84605f41e559f1881b0912b44099d0a2ac9bf46b3474823f10fb393b0e6 \
+ --hash=sha256:c13f325cf242bad135c350629eeb5d54b24228eb472fb3e2e9ebbd4c5dc20ca0 \
+ --hash=sha256:f05bcadf9a2a6b8dda047007075135fb7d08c73d9177aabc067e1be46881a201 \
+ --hash=sha256:fcbe42a4ac09d3ec9c987ddfcd956afd0b15f1ff613bd8371bde9405ffd5c8e5
# via
# google-api-core
# googleapis-common-protos
# proto-plus
-psycopg2==2.9.11 \
- --hash=sha256:103e857f46bb76908768ead4e2d0ba1d1a130e7b8ed77d3ae91e8b33481813e8 \
- --hash=sha256:210daed32e18f35e3140a1ebe059ac29209dd96468f2f7559aa59f75ee82a5cb \
- --hash=sha256:6ecddcf573777536bddfefaea8079ce959287798c8f5804bee6933635d538924 \
- --hash=sha256:8dc379166b5b7d5ea66dcebf433011dfc51a7bb8a5fc12367fa05668e5fc53c8 \
- --hash=sha256:964d31caf728e217c697ff77ea69c2ba0865fa41ec20bb00f0977e62fdcc52e3 \
- --hash=sha256:e03e4a6dbe87ff81540b434f2e5dc2bddad10296db5eea7bdc995bf5f4162938 \
- --hash=sha256:f10a48acba5fe6e312b891f290b4d2ca595fc9a06850fe53320beac353575578
+psycopg2==2.9.12 \
+ --hash=sha256:09826a6b89714626a662275d03f21639f1c68d183e2dcc9ba134d463a3da753e \
+ --hash=sha256:1dedb1c7a1d8552c4a6044c6b1c41a52e6a8e2d144af83eccac758076b1b7c15 \
+ --hash=sha256:2532c0cdc6ad18c9c35cd935cc3159712e14f05276a6d29a6435c52d24b840c1 \
+ --hash=sha256:3d23e684927d37b95cee9a943f6927b04ae2fdcd056fd0e2a30929ee89fee5a9 \
+ --hash=sha256:83d48e66e18c301d832e93c984a7bcbc0f4ac3bb79e2137e3bc335978c756dc0 \
+ --hash=sha256:a73d5513bfe929c56555006c7a9cc7ae6e4276aa99dd2b1e2544eb8bb54f8b23 \
+ --hash=sha256:d5fbe092315fb007c03544704e6d1e678a6c0378139d01cea433dc59edf041b4
# via barman
-pyasn1==0.6.2 \
- --hash=sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf \
- --hash=sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b
- # via
- # pyasn1-modules
- # rsa
+pyasn1==0.6.3 \
+ --hash=sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf \
+ --hash=sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde
+ # via pyasn1-modules
pyasn1-modules==0.4.2 \
--hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \
--hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6
@@ -621,9 +633,9 @@ pycparser==3.0 \
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \
--hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992
# via cffi
-pyjwt==2.11.0 \
- --hash=sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623 \
- --hash=sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469
+pyjwt==2.13.0 \
+ --hash=sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423 \
+ --hash=sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728
# via
# msal
# pyjwt
@@ -637,21 +649,17 @@ python-snappy==0.7.3 \
--hash=sha256:074c0636cfcd97e7251330f428064050ac81a52c62ed884fc2ddebbb60ed7f50 \
--hash=sha256:40216c1badfb2d38ac781ecb162a1d0ec40f8ee9747e610bcfefdfa79486cee3
# via barman
-requests==2.32.5 \
- --hash=sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 \
- --hash=sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf
+requests==2.34.2 \
+ --hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \
+ --hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed
# via
# azure-core
# google-api-core
# google-cloud-storage
# msal
-rsa==4.9.1 \
- --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \
- --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75
- # via google-auth
-s3transfer==0.16.0 \
- --hash=sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe \
- --hash=sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920
+s3transfer==0.17.0 \
+ --hash=sha256:9edeb6d1c3c2f89d6050348548834ad8289610d886e5bf7b7207728bd43ce33a \
+ --hash=sha256:ce3801712acf4ad3e89fb9990df97b4972e93f4b3b0004d214be5bce12814c20
# via boto3
six==1.17.0 \
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
@@ -664,15 +672,15 @@ typing-extensions==4.15.0 \
# azure-core
# azure-identity
# azure-storage-blob
-urllib3==2.6.3 \
- --hash=sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed \
- --hash=sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4
+urllib3==2.7.0 \
+ --hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \
+ --hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897
# via
# botocore
# requests
-zipp==3.23.0 \
- --hash=sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e \
- --hash=sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166
+zipp==4.1.0 \
+ --hash=sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f \
+ --hash=sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602
# via -r sidecar-requirements.in
zstandard==0.25.0 \
--hash=sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64 \
@@ -780,6 +788,4 @@ zstandard==0.25.0 \
setuptools==82.0.1 \
--hash=sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9 \
--hash=sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb
- # via
- # -r sidecar-requirements.in
- # barman
+ # via -r sidecar-requirements.in
diff --git a/dagger/check-doc-version/dagger.json b/dagger/check-doc-version/dagger.json
index 48c0a14..8f37cca 100644
--- a/dagger/check-doc-version/dagger.json
+++ b/dagger/check-doc-version/dagger.json
@@ -1,6 +1,6 @@
{
"name": "check-doc-version",
- "engineVersion": "v0.20.1",
+ "engineVersion": "v0.20.6",
"sdk": {
"source": "go"
},
diff --git a/dagger/check-doc-version/go.mod b/dagger/check-doc-version/go.mod
index 171aed8..57b4f76 100644
--- a/dagger/check-doc-version/go.mod
+++ b/dagger/check-doc-version/go.mod
@@ -4,46 +4,46 @@ go 1.25.0
require (
github.com/Khan/genqlient v0.8.1
- github.com/dagger/otel-go v1.41.0
- github.com/vektah/gqlparser/v2 v2.5.30
- go.opentelemetry.io/otel v1.41.0
- go.opentelemetry.io/otel/sdk v1.41.0
- go.opentelemetry.io/otel/trace v1.41.0
+ github.com/dagger/otel-go v1.43.0
+ github.com/vektah/gqlparser/v2 v2.5.32
+ go.opentelemetry.io/otel v1.43.0
+ go.opentelemetry.io/otel/sdk v1.43.0
+ go.opentelemetry.io/otel/trace v1.43.0
)
require (
- github.com/99designs/gqlgen v0.17.81 // indirect
+ github.com/99designs/gqlgen v0.17.89 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.17.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.17.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 // indirect
- go.opentelemetry.io/otel/log v0.17.0 // indirect
- go.opentelemetry.io/otel/metric v1.41.0 // indirect
- go.opentelemetry.io/otel/sdk/log v0.17.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.41.0 // indirect
- go.opentelemetry.io/proto/otlp v1.9.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- google.golang.org/grpc v1.79.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect
+ go.opentelemetry.io/otel/log v0.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.43.0 // indirect
+ go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.10.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ google.golang.org/grpc v1.80.0 // indirect
)
require (
- dagger.io/dagger v0.19.11
+ dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
- github.com/sosodev/duration v1.3.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
+ github.com/sosodev/duration v1.4.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect
- golang.org/x/net v0.51.0 // indirect
- golang.org/x/sys v0.41.0 // indirect
- golang.org/x/text v0.34.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
+ golang.org/x/net v0.53.0 // indirect
+ golang.org/x/sys v0.43.0 // indirect
+ golang.org/x/text v0.36.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
diff --git a/dagger/check-doc-version/go.sum b/dagger/check-doc-version/go.sum
index fe1c5ac..898c8fa 100644
--- a/dagger/check-doc-version/go.sum
+++ b/dagger/check-doc-version/go.sum
@@ -1,17 +1,19 @@
-dagger.io/dagger v0.19.11 h1:Cra3wL1oaZsqXJcnPydocx3bIDD5tM7XCuwcn2Uh+2Q=
-dagger.io/dagger v0.19.11/go.mod h1:BjAJWl4Lx7XRW7nooNjBi0ZAC5Ici2pkthkdBIZdbTI=
-github.com/99designs/gqlgen v0.17.81 h1:kCkN/xVyRb5rEQpuwOHRTYq83i0IuTQg9vdIiwEerTs=
-github.com/99designs/gqlgen v0.17.81/go.mod h1:vgNcZlLwemsUhYim4dC1pvFP5FX0pr2Y+uYUoHFb1ig=
+dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72 h1:s39e07WvaUU6tLhpojK8ZEIoIbOSn5hHOJra0waenxQ=
+dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72/go.mod h1:ZXg8+pQZaZUC8rAw4V/gPP8aKvKARIJZ+pfcV+RC1es=
+github.com/99designs/gqlgen v0.17.89 h1:KzEcxPiMgQoMw3m/E85atUEHyZyt0PbAflMia5Kw8z8=
+github.com/99designs/gqlgen v0.17.89/go.mod h1:GFqruTVGB7ZTdrf1uzOagpXbY7DrEt1pIxnTdhIbWvQ=
github.com/Khan/genqlient v0.8.1 h1:wtOCc8N9rNynRLXN3k3CnfzheCUNKBcvXmVv5zt6WCs=
github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU=
+github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
+github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/dagger/otel-go v1.41.0 h1:GQAJtTM1Ja9Dt/JSSqqjCFVlCye09Ymx4dWUDRqcgKw=
-github.com/dagger/otel-go v1.41.0/go.mod h1:RP74B3xmOq2MWL1lBsAWD9uvTryDhZ+m1dDzJj9QJEI=
+github.com/dagger/otel-go v1.43.0 h1:AYCnAamWmxtSxigWPTgC+8EWqiWPcDZEegh8y05gdJ8=
+github.com/dagger/otel-go v1.43.0/go.mod h1:83CTuXi70zcx1kaym5buqmb7RNzg1E9dEiQSFyLbLdU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -25,70 +27,70 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
-github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
-github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
+github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE=
+github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE=
-github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
+github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc=
+github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
-go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
+go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
+go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 h1:djrxvDxAe44mJUrKataUbOhCKhR3F8QCyWucO16hTQs=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0/go.mod h1:dt3nxpQEiSoKvfTVxp3TUg5fHPLhKtbcnN3Z1I1ePD0=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0 h1:VO3BL6OZXRQ1yQc8W6EVfJzINeJ35BkiHx4MYfoQf44=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0/go.mod h1:qRDnJ2nv3CQXMK2HUd9K9VtvedsPAce3S+/4LZHjX/s=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 h1:MMrOAN8H1FrvDyq9UJ4lu5/+ss49Qgfgb7Zpm0m8ABo=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0/go.mod h1:Na+2NNASJtF+uT4NxDe0G+NQb+bUgdPDfwxY/6JmS/c=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 h1:mq/Qcf28TWz719lE3/hMB4KkyDuLJIvgJnFGcd0kEUI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0/go.mod h1:yk5LXEYhsL2htyDNJbEq7fWzNEigeEdV5xBF/Y+kAv0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
-go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
-go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
-go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8=
-go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90=
+go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
+go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
+go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
+go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y=
-go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8=
-go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y=
-go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
-go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
-go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
-go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
+go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
+go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
+go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
+go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
+go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
+go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
-golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
-google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
-google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
+golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
+golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
+golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
+golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
+google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/dagger/e2e/dagger.json b/dagger/e2e/dagger.json
index 4b4d381..043bffb 100644
--- a/dagger/e2e/dagger.json
+++ b/dagger/e2e/dagger.json
@@ -1,6 +1,6 @@
{
"name": "e2e",
- "engineVersion": "v0.20.1",
+ "engineVersion": "v0.20.6",
"sdk": {
"source": "go"
},
diff --git a/dagger/e2e/go.mod b/dagger/e2e/go.mod
index 42c93d8..8e419c1 100644
--- a/dagger/e2e/go.mod
+++ b/dagger/e2e/go.mod
@@ -4,46 +4,46 @@ go 1.25.0
require (
github.com/Khan/genqlient v0.8.1
- github.com/dagger/otel-go v1.41.0
- github.com/vektah/gqlparser/v2 v2.5.30
- go.opentelemetry.io/otel v1.41.0
- go.opentelemetry.io/otel/sdk v1.41.0
- go.opentelemetry.io/otel/trace v1.41.0
+ github.com/dagger/otel-go v1.43.0
+ github.com/vektah/gqlparser/v2 v2.5.32
+ go.opentelemetry.io/otel v1.43.0
+ go.opentelemetry.io/otel/sdk v1.43.0
+ go.opentelemetry.io/otel/trace v1.43.0
)
require (
- github.com/99designs/gqlgen v0.17.81 // indirect
+ github.com/99designs/gqlgen v0.17.89 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.17.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.17.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 // indirect
- go.opentelemetry.io/otel/log v0.17.0 // indirect
- go.opentelemetry.io/otel/metric v1.41.0 // indirect
- go.opentelemetry.io/otel/sdk/log v0.17.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.41.0 // indirect
- go.opentelemetry.io/proto/otlp v1.9.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- google.golang.org/grpc v1.79.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect
+ go.opentelemetry.io/otel/log v0.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.43.0 // indirect
+ go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.10.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ google.golang.org/grpc v1.80.0 // indirect
)
require (
- dagger.io/dagger v0.19.11
+ dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
- github.com/sosodev/duration v1.3.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
+ github.com/sosodev/duration v1.4.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect
- golang.org/x/net v0.51.0 // indirect
- golang.org/x/sys v0.41.0 // indirect
- golang.org/x/text v0.34.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
+ golang.org/x/net v0.53.0 // indirect
+ golang.org/x/sys v0.43.0 // indirect
+ golang.org/x/text v0.36.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
diff --git a/dagger/e2e/go.sum b/dagger/e2e/go.sum
index fe1c5ac..898c8fa 100644
--- a/dagger/e2e/go.sum
+++ b/dagger/e2e/go.sum
@@ -1,17 +1,19 @@
-dagger.io/dagger v0.19.11 h1:Cra3wL1oaZsqXJcnPydocx3bIDD5tM7XCuwcn2Uh+2Q=
-dagger.io/dagger v0.19.11/go.mod h1:BjAJWl4Lx7XRW7nooNjBi0ZAC5Ici2pkthkdBIZdbTI=
-github.com/99designs/gqlgen v0.17.81 h1:kCkN/xVyRb5rEQpuwOHRTYq83i0IuTQg9vdIiwEerTs=
-github.com/99designs/gqlgen v0.17.81/go.mod h1:vgNcZlLwemsUhYim4dC1pvFP5FX0pr2Y+uYUoHFb1ig=
+dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72 h1:s39e07WvaUU6tLhpojK8ZEIoIbOSn5hHOJra0waenxQ=
+dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72/go.mod h1:ZXg8+pQZaZUC8rAw4V/gPP8aKvKARIJZ+pfcV+RC1es=
+github.com/99designs/gqlgen v0.17.89 h1:KzEcxPiMgQoMw3m/E85atUEHyZyt0PbAflMia5Kw8z8=
+github.com/99designs/gqlgen v0.17.89/go.mod h1:GFqruTVGB7ZTdrf1uzOagpXbY7DrEt1pIxnTdhIbWvQ=
github.com/Khan/genqlient v0.8.1 h1:wtOCc8N9rNynRLXN3k3CnfzheCUNKBcvXmVv5zt6WCs=
github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU=
+github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
+github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/dagger/otel-go v1.41.0 h1:GQAJtTM1Ja9Dt/JSSqqjCFVlCye09Ymx4dWUDRqcgKw=
-github.com/dagger/otel-go v1.41.0/go.mod h1:RP74B3xmOq2MWL1lBsAWD9uvTryDhZ+m1dDzJj9QJEI=
+github.com/dagger/otel-go v1.43.0 h1:AYCnAamWmxtSxigWPTgC+8EWqiWPcDZEegh8y05gdJ8=
+github.com/dagger/otel-go v1.43.0/go.mod h1:83CTuXi70zcx1kaym5buqmb7RNzg1E9dEiQSFyLbLdU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -25,70 +27,70 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
-github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
-github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
+github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE=
+github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE=
-github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
+github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc=
+github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
-go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
+go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
+go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 h1:djrxvDxAe44mJUrKataUbOhCKhR3F8QCyWucO16hTQs=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0/go.mod h1:dt3nxpQEiSoKvfTVxp3TUg5fHPLhKtbcnN3Z1I1ePD0=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0 h1:VO3BL6OZXRQ1yQc8W6EVfJzINeJ35BkiHx4MYfoQf44=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0/go.mod h1:qRDnJ2nv3CQXMK2HUd9K9VtvedsPAce3S+/4LZHjX/s=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 h1:MMrOAN8H1FrvDyq9UJ4lu5/+ss49Qgfgb7Zpm0m8ABo=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0/go.mod h1:Na+2NNASJtF+uT4NxDe0G+NQb+bUgdPDfwxY/6JmS/c=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 h1:mq/Qcf28TWz719lE3/hMB4KkyDuLJIvgJnFGcd0kEUI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0/go.mod h1:yk5LXEYhsL2htyDNJbEq7fWzNEigeEdV5xBF/Y+kAv0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
-go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
-go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
-go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8=
-go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90=
+go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
+go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
+go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
+go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y=
-go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8=
-go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y=
-go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
-go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
-go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
-go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
+go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
+go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
+go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
+go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
+go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
+go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
-golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
-google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
-google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
+golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
+golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
+golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
+golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
+google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/dagger/gotest/dagger.json b/dagger/gotest/dagger.json
index b8efa40..7c9937c 100644
--- a/dagger/gotest/dagger.json
+++ b/dagger/gotest/dagger.json
@@ -1,6 +1,6 @@
{
"name": "gotest",
- "engineVersion": "v0.20.1",
+ "engineVersion": "v0.20.6",
"sdk": {
"source": "go"
},
diff --git a/dagger/gotest/go.mod b/dagger/gotest/go.mod
index b6354ba..dfc9259 100644
--- a/dagger/gotest/go.mod
+++ b/dagger/gotest/go.mod
@@ -4,46 +4,46 @@ go 1.25.0
require (
github.com/Khan/genqlient v0.8.1
- github.com/dagger/otel-go v1.41.0
- github.com/vektah/gqlparser/v2 v2.5.30
- go.opentelemetry.io/otel v1.41.0
- go.opentelemetry.io/otel/sdk v1.41.0
- go.opentelemetry.io/otel/trace v1.41.0
+ github.com/dagger/otel-go v1.43.0
+ github.com/vektah/gqlparser/v2 v2.5.32
+ go.opentelemetry.io/otel v1.43.0
+ go.opentelemetry.io/otel/sdk v1.43.0
+ go.opentelemetry.io/otel/trace v1.43.0
)
require (
- github.com/99designs/gqlgen v0.17.81 // indirect
+ github.com/99designs/gqlgen v0.17.89 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.17.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.17.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 // indirect
- go.opentelemetry.io/otel/log v0.17.0 // indirect
- go.opentelemetry.io/otel/sdk/log v0.17.0 // indirect
- go.opentelemetry.io/proto/otlp v1.9.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- google.golang.org/grpc v1.79.1 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect
+ go.opentelemetry.io/otel/log v0.19.0 // indirect
+ go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.10.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ google.golang.org/grpc v1.80.0 // indirect
)
require (
- dagger.io/dagger v0.19.11
+ dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
- github.com/sosodev/duration v1.3.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
+ github.com/sosodev/duration v1.4.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect
- go.opentelemetry.io/otel/metric v1.41.0 // indirect
- go.opentelemetry.io/otel/sdk/metric v1.41.0 // indirect
- golang.org/x/net v0.51.0 // indirect
- golang.org/x/sys v0.41.0 // indirect
- golang.org/x/text v0.34.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
+ go.opentelemetry.io/otel/metric v1.43.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
+ golang.org/x/net v0.53.0 // indirect
+ golang.org/x/sys v0.43.0 // indirect
+ golang.org/x/text v0.36.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)
diff --git a/dagger/gotest/go.sum b/dagger/gotest/go.sum
index fe1c5ac..898c8fa 100644
--- a/dagger/gotest/go.sum
+++ b/dagger/gotest/go.sum
@@ -1,17 +1,19 @@
-dagger.io/dagger v0.19.11 h1:Cra3wL1oaZsqXJcnPydocx3bIDD5tM7XCuwcn2Uh+2Q=
-dagger.io/dagger v0.19.11/go.mod h1:BjAJWl4Lx7XRW7nooNjBi0ZAC5Ici2pkthkdBIZdbTI=
-github.com/99designs/gqlgen v0.17.81 h1:kCkN/xVyRb5rEQpuwOHRTYq83i0IuTQg9vdIiwEerTs=
-github.com/99designs/gqlgen v0.17.81/go.mod h1:vgNcZlLwemsUhYim4dC1pvFP5FX0pr2Y+uYUoHFb1ig=
+dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72 h1:s39e07WvaUU6tLhpojK8ZEIoIbOSn5hHOJra0waenxQ=
+dagger.io/dagger v0.20.6-0.20260415192040-7058e9313c72/go.mod h1:ZXg8+pQZaZUC8rAw4V/gPP8aKvKARIJZ+pfcV+RC1es=
+github.com/99designs/gqlgen v0.17.89 h1:KzEcxPiMgQoMw3m/E85atUEHyZyt0PbAflMia5Kw8z8=
+github.com/99designs/gqlgen v0.17.89/go.mod h1:GFqruTVGB7ZTdrf1uzOagpXbY7DrEt1pIxnTdhIbWvQ=
github.com/Khan/genqlient v0.8.1 h1:wtOCc8N9rNynRLXN3k3CnfzheCUNKBcvXmVv5zt6WCs=
github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU=
+github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
+github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/dagger/otel-go v1.41.0 h1:GQAJtTM1Ja9Dt/JSSqqjCFVlCye09Ymx4dWUDRqcgKw=
-github.com/dagger/otel-go v1.41.0/go.mod h1:RP74B3xmOq2MWL1lBsAWD9uvTryDhZ+m1dDzJj9QJEI=
+github.com/dagger/otel-go v1.43.0 h1:AYCnAamWmxtSxigWPTgC+8EWqiWPcDZEegh8y05gdJ8=
+github.com/dagger/otel-go v1.43.0/go.mod h1:83CTuXi70zcx1kaym5buqmb7RNzg1E9dEiQSFyLbLdU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -25,70 +27,70 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
-github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
-github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
+github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE=
+github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE=
-github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
+github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc=
+github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
-go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
+go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
+go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 h1:djrxvDxAe44mJUrKataUbOhCKhR3F8QCyWucO16hTQs=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0/go.mod h1:dt3nxpQEiSoKvfTVxp3TUg5fHPLhKtbcnN3Z1I1ePD0=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0 h1:VO3BL6OZXRQ1yQc8W6EVfJzINeJ35BkiHx4MYfoQf44=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.41.0/go.mod h1:qRDnJ2nv3CQXMK2HUd9K9VtvedsPAce3S+/4LZHjX/s=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0 h1:MMrOAN8H1FrvDyq9UJ4lu5/+ss49Qgfgb7Zpm0m8ABo=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.41.0/go.mod h1:Na+2NNASJtF+uT4NxDe0G+NQb+bUgdPDfwxY/6JmS/c=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 h1:mq/Qcf28TWz719lE3/hMB4KkyDuLJIvgJnFGcd0kEUI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0/go.mod h1:yk5LXEYhsL2htyDNJbEq7fWzNEigeEdV5xBF/Y+kAv0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
-go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
-go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
-go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8=
-go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90=
+go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
+go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
+go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
+go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4=
go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y=
-go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8=
-go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y=
-go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
-go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
-go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
-go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
+go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
+go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
+go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
+go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
+go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
+go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
-golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
-golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
-google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
-google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
+golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
+golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
+golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
+golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
+google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
+google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/go.mod b/go.mod
index fdd5b81..7813e62 100644
--- a/go.mod
+++ b/go.mod
@@ -1,37 +1,36 @@
module github.com/cloudnative-pg/plugin-barman-cloud
-go 1.25.0
-
-toolchain go1.26.1
+go 1.26.3
require (
- github.com/cert-manager/cert-manager v1.19.4
- github.com/cloudnative-pg/api v1.28.1
- github.com/cloudnative-pg/barman-cloud v0.5.0
- github.com/cloudnative-pg/cloudnative-pg v1.28.1
- github.com/cloudnative-pg/cnpg-i v0.3.1
+ github.com/cert-manager/cert-manager v1.20.2
+ github.com/cloudnative-pg/api v1.29.1
+ github.com/cloudnative-pg/barman-cloud v0.5.1
+ github.com/cloudnative-pg/cloudnative-pg v1.29.1
+ github.com/cloudnative-pg/cnpg-i v0.5.0
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2
- github.com/cloudnative-pg/machinery v0.3.3
- github.com/onsi/ginkgo/v2 v2.28.1
- github.com/onsi/gomega v1.39.1
+ github.com/cloudnative-pg/machinery v0.5.0
+ github.com/onsi/ginkgo/v2 v2.29.0
+ github.com/onsi/gomega v1.41.0
github.com/spf13/cobra v1.10.2
github.com/spf13/viper v1.21.0
- google.golang.org/grpc v1.79.3
+ google.golang.org/grpc v1.81.1
gopkg.in/yaml.v3 v3.0.1
- k8s.io/api v0.35.2
- k8s.io/apiextensions-apiserver v0.35.2
- k8s.io/apimachinery v0.35.2
- k8s.io/client-go v0.35.2
- k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2
- sigs.k8s.io/controller-runtime v0.23.3
+ k8s.io/api v0.36.1
+ k8s.io/apiextensions-apiserver v0.36.1
+ k8s.io/apimachinery v0.36.1
+ k8s.io/client-go v0.36.1
+ k8s.io/utils v0.0.0-20260507154919-ff6756f316d2
+ sigs.k8s.io/controller-runtime v0.24.1
sigs.k8s.io/kustomize/api v0.21.1
sigs.k8s.io/kustomize/kyaml v0.21.1
)
require (
cel.dev/expr v0.25.1 // indirect
- github.com/Masterminds/semver/v3 v3.4.0 // indirect
+ github.com/Masterminds/semver/v3 v3.5.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
+ github.com/avast/retry-go/v5 v5.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
@@ -41,52 +40,50 @@ require (
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
- github.com/fxamacker/cbor/v2 v2.9.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.9.1 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
- github.com/go-openapi/jsonpointer v0.22.4 // indirect
- github.com/go-openapi/jsonreference v0.21.4 // indirect
- github.com/go-openapi/swag v0.25.4 // indirect
- github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
- github.com/go-openapi/swag/conv v0.25.4 // indirect
- github.com/go-openapi/swag/fileutils v0.25.4 // indirect
- github.com/go-openapi/swag/jsonname v0.25.4 // indirect
- github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
- github.com/go-openapi/swag/loading v0.25.4 // indirect
- github.com/go-openapi/swag/mangling v0.25.4 // indirect
- github.com/go-openapi/swag/netutils v0.25.4 // indirect
- github.com/go-openapi/swag/stringutils v0.25.4 // indirect
- github.com/go-openapi/swag/typeutils v0.25.4 // indirect
- github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/jsonreference v0.21.5 // indirect
+ github.com/go-openapi/swag v0.26.0 // indirect
+ github.com/go-openapi/swag/cmdutils v0.26.0 // indirect
+ github.com/go-openapi/swag/conv v0.26.0 // indirect
+ github.com/go-openapi/swag/fileutils v0.26.0 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.0 // indirect
+ github.com/go-openapi/swag/jsonutils v0.26.0 // indirect
+ github.com/go-openapi/swag/loading v0.26.0 // indirect
+ github.com/go-openapi/swag/mangling v0.26.0 // indirect
+ github.com/go-openapi/swag/netutils v0.26.0 // indirect
+ github.com/go-openapi/swag/stringutils v0.26.0 // indirect
+ github.com/go-openapi/swag/typeutils v0.26.0 // indirect
+ github.com/go-openapi/swag/yamlutils v0.26.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
- github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.26.0 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
- github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
+ github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.4.0 // indirect
- github.com/lib/pq v1.11.1 // indirect
- github.com/moby/spdystream v0.5.0 // indirect
+ github.com/lib/pq v1.12.3 // indirect
+ github.com/moby/spdystream v0.5.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.87.1 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
- github.com/prometheus/common v0.67.4 // indirect
+ github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.19.2 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/snorwin/jsonpatch v1.5.0 // indirect
@@ -100,42 +97,43 @@ require (
github.com/x448/float16 v0.8.4 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
- go.opentelemetry.io/otel v1.40.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect
- go.opentelemetry.io/otel/metric v1.40.0 // indirect
- go.opentelemetry.io/otel/sdk v1.40.0 // indirect
- go.opentelemetry.io/otel/trace v1.40.0 // indirect
- go.opentelemetry.io/proto/otlp v1.7.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
+ go.opentelemetry.io/otel v1.43.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect
+ go.opentelemetry.io/otel/metric v1.43.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.43.0 // indirect
+ go.opentelemetry.io/otel/trace v1.43.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
- go.uber.org/zap v1.27.1 // indirect
- go.yaml.in/yaml/v2 v2.4.3 // indirect
+ go.uber.org/zap v1.28.0 // indirect
+ go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect
- golang.org/x/mod v0.32.0 // indirect
- golang.org/x/net v0.49.0 // indirect
- golang.org/x/oauth2 v0.34.0 // indirect
- golang.org/x/sync v0.19.0 // indirect
- golang.org/x/sys v0.42.0 // indirect
- golang.org/x/term v0.39.0 // indirect
- golang.org/x/text v0.33.0 // indirect
- golang.org/x/time v0.14.0 // indirect
- golang.org/x/tools v0.41.0 // indirect
+ golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
+ golang.org/x/mod v0.35.0 // indirect
+ golang.org/x/net v0.53.0 // indirect
+ golang.org/x/oauth2 v0.36.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ golang.org/x/sys v0.45.0 // indirect
+ golang.org/x/term v0.42.0 // indirect
+ golang.org/x/text v0.36.0 // indirect
+ golang.org/x/time v0.15.0 // indirect
+ golang.org/x/tools v0.44.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
- google.golang.org/protobuf v1.36.11 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 // indirect
+ google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- k8s.io/apiserver v0.35.2 // indirect
- k8s.io/component-base v0.35.2 // indirect
- k8s.io/klog/v2 v2.130.1 // indirect
- k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // indirect
- sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 // indirect
- sigs.k8s.io/gateway-api v1.4.0 // indirect
+ k8s.io/apiserver v0.36.1 // indirect
+ k8s.io/component-base v0.36.1 // indirect
+ k8s.io/klog/v2 v2.140.0 // indirect
+ k8s.io/kube-openapi v0.0.0-20260502001324-b7f5293f4787 // indirect
+ k8s.io/streaming v0.36.1 // indirect
+ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect
+ sigs.k8s.io/gateway-api v1.5.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
- sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
+ sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)
diff --git a/go.sum b/go.sum
index 6b7e8f4..2ccdba4 100644
--- a/go.sum
+++ b/go.sum
@@ -1,33 +1,35 @@
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
-github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
-github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE=
+github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/avast/retry-go/v5 v5.0.0 h1:kf1Qc2UsTZ4qq8elDymqfbISvkyMuhgRxuJqX2NHP7k=
+github.com/avast/retry-go/v5 v5.0.0/go.mod h1://d+usmKWio1agtZfS1H/ltTqwtIfBnRq9zEwjc3eH8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
-github.com/cert-manager/cert-manager v1.19.4 h1:7lOkSYj+nJNjgGFfAznQzPpOfWX+1Kgz6xUXwTa/K5k=
-github.com/cert-manager/cert-manager v1.19.4/go.mod h1:9uBnn3IK9NxjjuXmQDYhwOwFUU5BtGVB1g/voPvvcVw=
+github.com/cert-manager/cert-manager v1.20.2 h1:CimnY00nLqB2lmxhoSuEC4GDMFDK7JCXqyjwMM9ndIQ=
+github.com/cert-manager/cert-manager v1.20.2/go.mod h1:1g/+a/WK5zWH/dXPZa3dMD3aJQJNRXQu+PN17C6WrOw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cloudnative-pg/api v1.28.1 h1:hp/TDgR+RrTa4EMp/pAKZia+kZ52i8ZPLG+JG10eeVU=
-github.com/cloudnative-pg/api v1.28.1/go.mod h1:J0RTwrOYxQP17N1YMrDxcUmr/0wPYHQW179P7ibkVsM=
-github.com/cloudnative-pg/barman-cloud v0.5.0 h1:DykSaX4o7ee2vyu5FQoG1RJsntHd+EIttIKZbJPlB1Q=
-github.com/cloudnative-pg/barman-cloud v0.5.0/go.mod h1:SO2HzLa+GWlSIpGyxnISoJAFPIcaa/qDa33Bb3jefac=
-github.com/cloudnative-pg/cloudnative-pg v1.28.1 h1:HdOUWgFhta558uHfXeO/199qCApxaj5yi05x6nWNmgs=
-github.com/cloudnative-pg/cloudnative-pg v1.28.1/go.mod h1:yhRa4GqJAjNd0tT9AiRgk1KdqLhMjo/JmGGoASRl2CU=
-github.com/cloudnative-pg/cnpg-i v0.3.1 h1:fKj8NoToWI11HUL2UWYJBpkVzmaTvbs3kDMo7wQF8RU=
-github.com/cloudnative-pg/cnpg-i v0.3.1/go.mod h1:glRDiJLJY51FY8ScJIv/OkaGJxFnojJkkNAqSy5XC6s=
+github.com/cloudnative-pg/api v1.29.1 h1:FWr8S7EQeOfdhYXyr2cof8wUXLARZiiQt5Qa6ltED7w=
+github.com/cloudnative-pg/api v1.29.1/go.mod h1:QtWF3yzSvIfORMHaSkPAk/o3bhCJwEHJgN3riyRiz3o=
+github.com/cloudnative-pg/barman-cloud v0.5.1 h1:vjkXrrxo2DQXHT9u9usqhtaHiPZ/lTfDVs/pIWYTepQ=
+github.com/cloudnative-pg/barman-cloud v0.5.1/go.mod h1:XPc5IUFP1y4cZX1sg+Pd8j9V4tmUEVnv3BGCpfQOOg8=
+github.com/cloudnative-pg/cloudnative-pg v1.29.1 h1:ZNEt1TMlnQKXI1kho2UqQuqdfvIvjGln4kN7C1lsmGA=
+github.com/cloudnative-pg/cloudnative-pg v1.29.1/go.mod h1:Sbgx9jVmkle4/gR2U5JHrzDd74sRPOBHDtPkvncg5v8=
+github.com/cloudnative-pg/cnpg-i v0.5.0 h1:/TOzpNT6cwNgrpftTtrnLKdoHgMwd+88vZgXjlVgXeE=
+github.com/cloudnative-pg/cnpg-i v0.5.0/go.mod h1:7Gh4+UzhBpGhr4DreB1GN9wGYfvxwXCXZUyVt3zE/3I=
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2 h1:0reS9MtyLYINHXQ/MfxJ9jp39hhBf8e3Qdj+T5Nsq6I=
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2/go.mod h1:gvrKabgxXq0zGthXGucemDdsxakLEQDMxn43M4HLW30=
-github.com/cloudnative-pg/machinery v0.3.3 h1:CaqXqLTJH9RrVv3R/YU0NmFaI/F18HLg2JfH3mQLcDk=
-github.com/cloudnative-pg/machinery v0.3.3/go.mod h1:RYAYlVKBF5pH4mg+Q8wHjNDyENV9ajbkG41zOEf8DEs=
+github.com/cloudnative-pg/machinery v0.5.0 h1:hhTnkzn+AiN3NmbjCQ6RXj5rfqV3K6arzq6kdXAzcnQ=
+github.com/cloudnative-pg/machinery v0.5.0/go.mod h1:uuFjqBUjWn0a9uvAk1ixTSzPM0PrjaS+QiKLOIBqLm4=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
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=
@@ -45,8 +47,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
-github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
-github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
+github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
+github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
@@ -64,40 +66,40 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=
-github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=
-github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
-github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
-github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
-github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
-github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
-github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
-github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
-github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
-github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
-github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
-github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
-github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
-github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
-github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
-github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
-github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
-github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
-github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
-github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
-github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
-github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
-github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
-github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
-github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
-github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
-github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
-github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
-github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
-github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
-github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
-github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
+github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
+github.com/go-openapi/swag v0.26.0 h1:GVDXCmfvhfu1BxiHo8/FA+BbKmhecHnG3varjON5/RI=
+github.com/go-openapi/swag v0.26.0/go.mod h1:82g3193sZJRbocs7bNCqGfIgq8pkuwVwCfhKIRlEQF0=
+github.com/go-openapi/swag/cmdutils v0.26.0 h1:iowihOcvq7y4egO8cOq0dmfohz6wfeQ63U1EnuhO2TU=
+github.com/go-openapi/swag/cmdutils v0.26.0/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
+github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=
+github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=
+github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU=
+github.com/go-openapi/swag/fileutils v0.26.0/go.mod h1:0WDJ7lp67eNjPMO50wAWYlKvhOb6CQ37rzR7wrgI8Tc=
+github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
+github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
+github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA=
+github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y=
+github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko=
+github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg=
+github.com/go-openapi/swag/mangling v0.26.0 h1:Du2YC4YLA/Y5m/YKQd7AnY5qq0wRKSFZTTt8ktFaXcQ=
+github.com/go-openapi/swag/mangling v0.26.0/go.mod h1:jifS7W9vbg+pw63bT+GI53otluMQL3CeemuyCHKwVx0=
+github.com/go-openapi/swag/netutils v0.26.0 h1:CmZp+ZT7HrmFwrC3GdGsXBq2+42T1bjKBapcqVpIs3c=
+github.com/go-openapi/swag/netutils v0.26.0/go.mod h1:5iK+Ok3ZohWWex1C50BFTPexi03UaPwjW4Oj8kgrpwo=
+github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg=
+github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE=
+github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4=
+github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=
+github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ=
+github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=
+github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=
+github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
+github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
@@ -106,8 +108,6 @@ github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
-github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
@@ -117,16 +117,16 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
-github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
+github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
+github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
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/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE=
@@ -143,14 +143,14 @@ github.com/kubernetes-csi/external-snapshotter/client/v8 v8.4.0 h1:bMqrb3UHgHbP+
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.4.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
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/lib/pq v1.11.1 h1:wuChtj2hfsGmmx3nf1m7xC2XpK6OtelS2shMY+bGMtI=
-github.com/lib/pq v1.11.1/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
+github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
+github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
-github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
-github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y=
+github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -161,12 +161,10 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
-github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
-github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
-github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
+github.com/onsi/ginkgo/v2 v2.29.0 h1:rfh+ZFjgJhYWRoIqVf3Uwx/W20yLrcrE2h2GmYVRaag=
+github.com/onsi/ginkgo/v2 v2.29.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
+github.com/onsi/gomega v1.41.0 h1:OwKp4pXNgVxf6sCplzYo794OFNuoL2q2SBMU5NSWOjA=
+github.com/onsi/gomega v1.41.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -180,8 +178,8 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
-github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
-github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
+github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
+github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
@@ -239,66 +237,66 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
-go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
-go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI=
-go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
-go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
-go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
-go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
-go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
-go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
-go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
-go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
+go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
+go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs=
+go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
+go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
+go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
+go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
+go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
+go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
+go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
+go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
+go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
+go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
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.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
-go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
-go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
-go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
+go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
+go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
+go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
+go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
-golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4=
-golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
-golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
-golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
-golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
-golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
-golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
-golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
-golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
-golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
-golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
-golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
+golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
+golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
+golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
+golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
+golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
+golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
+golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
+golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
+golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
+golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
+golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
+golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
-gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
-gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
-google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
-google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
-google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
-google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
-google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
-google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
+gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
+google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
+google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 h1:ndE4FoJqsIceKP2oYSnUZqhTdYufCYYkqwtFzfrhI7w=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
+google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
+google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
+google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -310,30 +308,32 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
-k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
-k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
-k8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0=
-k8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU=
-k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
-k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
-k8s.io/apiserver v0.35.2 h1:rb52v0CZGEL0FkhjS+I6jHflAp7fZ4MIaKcEHX7wmDk=
-k8s.io/apiserver v0.35.2/go.mod h1:CROJUAu0tfjZLyYgSeBsBan2T7LUJGh0ucWwTCSSk7g=
-k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
-k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
-k8s.io/component-base v0.35.2 h1:btgR+qNrpWuRSuvWSnQYsZy88yf5gVwemvz0yw79pGc=
-k8s.io/component-base v0.35.2/go.mod h1:B1iBJjooe6xIJYUucAxb26RwhAjzx0gHnqO9htWIX+0=
-k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
-k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ=
-k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
-k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 h1:qPrZsv1cwQiFeieFlRqT627fVZ+tyfou/+S5S0H5ua0=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
-sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
-sigs.k8s.io/gateway-api v1.4.0 h1:ZwlNM6zOHq0h3WUX2gfByPs2yAEsy/EenYJB78jpQfQ=
-sigs.k8s.io/gateway-api v1.4.0/go.mod h1:AR5RSqciWP98OPckEjOjh2XJhAe2Na4LHyXD2FUY7Qk=
+k8s.io/api v0.36.1 h1:XbL/EMj8K2aJpJtePmqUyQMsM0D4QI2pvl7YKJ20FTY=
+k8s.io/api v0.36.1/go.mod h1:KOWo4ey3TINlXjeHVuwB3i+tXXnu+UcwFBHlI/9dvEo=
+k8s.io/apiextensions-apiserver v0.36.1 h1:6JfYmPUsuUIHuN+3QxutXYWj492RqF5fBSx67GYK5Ks=
+k8s.io/apiextensions-apiserver v0.36.1/go.mod h1:pLzZin90riwisdzKwv/GoTwENooytoIx5zWJb4Hkby8=
+k8s.io/apimachinery v0.36.1 h1:G63Gjx2W+q0YD+72Vo8oY0nDnePVwnuzTmmy5ENrVSA=
+k8s.io/apimachinery v0.36.1/go.mod h1:ibYOR00vW/I1kzvi5SF0dRuJ52BvKtfvRdOn35GPQ+8=
+k8s.io/apiserver v0.36.1 h1:iMS5V+rPUertv5P9RaqJgmHHTuh4quWpoxchvMUY+JY=
+k8s.io/apiserver v0.36.1/go.mod h1:Cby1PbLWztu0GDOxoO6iFOyyqIsziHNEW+w9zVQ22Kw=
+k8s.io/client-go v0.36.1 h1:FN/K8QIT2CEDt+2WB2HnWrUANZ50AP5GII43/SP2JR0=
+k8s.io/client-go v0.36.1/go.mod h1:s6rAnCtTGYDQnpNjEhSaISV+2O8jwruZ6m3QOYBFbtU=
+k8s.io/component-base v0.36.1 h1:iG6GsELftXqTNG9HG6kiVjatSgAw1sf5pJ6R5a6N0kA=
+k8s.io/component-base v0.36.1/go.mod h1:nf9XPlntRdqO6WMeEWAA5F93Y4ICZQdeT9GeqLDB3JI=
+k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
+k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
+k8s.io/kube-openapi v0.0.0-20260502001324-b7f5293f4787 h1:kHv8PETbPIVHfqKBYwTNNSjqChf/7xn3JOS3re+NWs8=
+k8s.io/kube-openapi v0.0.0-20260502001324-b7f5293f4787/go.mod h1:Cyq7UE0QtGe+Zo+/6XFrxiS4Mq0tLyQEONkFzSkfp9o=
+k8s.io/streaming v0.36.1 h1:L+K68n4Gg940BGNNYtUBvL1WTLL0YnKT3s+P1MNAmR4=
+k8s.io/streaming v0.36.1/go.mod h1:z6fV3D+NVkoeqRMtWwlUZK6U17SY/LqNzOxWL6GyR/s=
+k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc=
+k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
+sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4=
+sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw=
+sigs.k8s.io/gateway-api v1.5.0 h1:duoo14Ky/fJXpjpmyMISE2RTBGnfCg8zICfTYLTnBJA=
+sigs.k8s.io/gateway-api v1.5.0/go.mod h1:GvCETiaMAlLym5CovLxGjS0NysqFk3+Yuq3/rh6QL2o=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs=
@@ -342,7 +342,7 @@ sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7
sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs=
-sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0 h1:qmp2e3ZfFi1/jJbDGpD4mt3wyp6PE1NfKHCYLqgNQJo=
+sigs.k8s.io/structured-merge-diff/v6 v6.4.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
diff --git a/internal/cmd/restore/main.go b/internal/cmd/restore/main.go
index 72d9cd0..9448d5b 100644
--- a/internal/cmd/restore/main.go
+++ b/internal/cmd/restore/main.go
@@ -57,6 +57,8 @@ func NewCmd() *cobra.Command {
_ = viper.BindEnv("pod-name", "POD_NAME")
_ = viper.BindEnv("pgdata", "PGDATA")
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
+ _ = viper.BindEnv("custom-cnpg-group", "CUSTOM_CNPG_GROUP")
+ _ = viper.BindEnv("custom-cnpg-version", "CUSTOM_CNPG_VERSION")
return cmd
}
diff --git a/internal/cnpgi/common/scheme.go b/internal/cnpgi/common/scheme.go
new file mode 100644
index 0000000..8f74015
--- /dev/null
+++ b/internal/cnpgi/common/scheme.go
@@ -0,0 +1,66 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+import (
+ "context"
+
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ "github.com/cloudnative-pg/machinery/pkg/log"
+ "github.com/spf13/viper"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+
+ barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+)
+
+// GenerateScheme creates a runtime.Scheme object with all the
+// definition needed to support the sidecar. This allows
+// the plugin to be used in every CNPG-based operator.
+func GenerateScheme(ctx context.Context) *runtime.Scheme {
+ result := runtime.NewScheme()
+
+ barmancloudv1.AddKnownTypes(result)
+ utilruntime.Must(clientgoscheme.AddToScheme(result))
+
+ cnpgGroup := viper.GetString("custom-cnpg-group")
+ cnpgVersion := viper.GetString("custom-cnpg-version")
+ if len(cnpgGroup) == 0 {
+ cnpgGroup = cnpgv1.SchemeGroupVersion.Group
+ }
+ if len(cnpgVersion) == 0 {
+ cnpgVersion = cnpgv1.SchemeGroupVersion.Version
+ }
+
+ // Proceed with custom registration of the CNPG scheme
+ schemeGroupVersion := schema.GroupVersion{Group: cnpgGroup, Version: cnpgVersion}
+ result.AddKnownTypes(schemeGroupVersion,
+ &cnpgv1.Cluster{}, &cnpgv1.ClusterList{},
+ &cnpgv1.Backup{}, &cnpgv1.BackupList{},
+ &cnpgv1.ScheduledBackup{}, &cnpgv1.ScheduledBackupList{},
+ )
+
+ schemeLog := log.FromContext(ctx)
+ schemeLog.Info("CNPG types registration", "schemeGroupVersion", schemeGroupVersion)
+
+ return result
+}
diff --git a/internal/cnpgi/instance/internal/client/client_test.go b/internal/cnpgi/instance/internal/client/client_test.go
index c7d2fa6..48947a0 100644
--- a/internal/cnpgi/instance/internal/client/client_test.go
+++ b/internal/cnpgi/instance/internal/client/client_test.go
@@ -39,7 +39,7 @@ var scheme = buildScheme()
func buildScheme() *runtime.Scheme {
scheme := runtime.NewScheme()
_ = corev1.AddToScheme(scheme)
- _ = barmancloudv1.AddToScheme(scheme)
+ barmancloudv1.AddKnownTypes(scheme)
return scheme
}
diff --git a/internal/cnpgi/instance/manager.go b/internal/cnpgi/instance/manager.go
index 7c14878..afe7d04 100644
--- a/internal/cnpgi/instance/manager.go
+++ b/internal/cnpgi/instance/manager.go
@@ -27,22 +27,18 @@ import (
"github.com/cloudnative-pg/machinery/pkg/log"
"github.com/spf13/viper"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
- utilruntime "k8s.io/apimachinery/pkg/util/runtime"
- clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/scheme"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common"
extendedclient "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/instance/internal/client"
)
// Start starts the sidecar informers and CNPG-i server
func Start(ctx context.Context) error {
- scheme := generateScheme(ctx)
+ scheme := common.GenerateScheme(ctx)
setupLog := log.FromContext(ctx)
setupLog.Info("Starting barman cloud instance plugin")
@@ -118,35 +114,3 @@ func Start(ctx context.Context) error {
return nil
}
-
-// generateScheme creates a runtime.Scheme object with all the
-// definition needed to support the sidecar. This allows
-// the plugin to be used in every CNPG-based operator.
-func generateScheme(ctx context.Context) *runtime.Scheme {
- result := runtime.NewScheme()
-
- utilruntime.Must(barmancloudv1.AddToScheme(result))
- utilruntime.Must(clientgoscheme.AddToScheme(result))
-
- cnpgGroup := viper.GetString("custom-cnpg-group")
- cnpgVersion := viper.GetString("custom-cnpg-version")
- if len(cnpgGroup) == 0 {
- cnpgGroup = cnpgv1.SchemeGroupVersion.Group
- }
- if len(cnpgVersion) == 0 {
- cnpgVersion = cnpgv1.SchemeGroupVersion.Version
- }
-
- // Proceed with custom registration of the CNPG scheme
- schemeGroupVersion := schema.GroupVersion{Group: cnpgGroup, Version: cnpgVersion}
- schemeBuilder := &scheme.Builder{GroupVersion: schemeGroupVersion}
- schemeBuilder.Register(&cnpgv1.Cluster{}, &cnpgv1.ClusterList{})
- schemeBuilder.Register(&cnpgv1.Backup{}, &cnpgv1.BackupList{})
- schemeBuilder.Register(&cnpgv1.ScheduledBackup{}, &cnpgv1.ScheduledBackupList{})
- utilruntime.Must(schemeBuilder.AddToScheme(result))
-
- schemeLog := log.FromContext(ctx)
- schemeLog.Info("CNPG types registration", "schemeGroupVersion", schemeGroupVersion)
-
- return result
-}
diff --git a/internal/cnpgi/instance/metrics_test.go b/internal/cnpgi/instance/metrics_test.go
index 963332f..6976d81 100644
--- a/internal/cnpgi/instance/metrics_test.go
+++ b/internal/cnpgi/instance/metrics_test.go
@@ -55,7 +55,7 @@ var _ = Describe("Metrics Collect method", func() {
BeforeEach(func() {
ctx = context.Background()
scheme := runtime.NewScheme()
- Expect(barmancloudv1.AddToScheme(scheme)).To(Succeed())
+ barmancloudv1.AddKnownTypes(scheme)
// Timestamps for the test
firstRecoverabilityPoint := metav1.NewTime(time.Now().Add(-24 * time.Hour))
diff --git a/internal/cnpgi/instance/retention.go b/internal/cnpgi/instance/retention.go
index 372d50e..4176956 100644
--- a/internal/cnpgi/instance/retention.go
+++ b/internal/cnpgi/instance/retention.go
@@ -81,6 +81,8 @@ func (c *CatalogMaintenanceRunnable) Start(ctx context.Context) error {
// cycle enforces the retention policies. On success, it returns the amount
// of time to wait to the next check.
func (c *CatalogMaintenanceRunnable) cycle(ctx context.Context) (time.Duration, error) {
+ contextLogger := log.FromContext(ctx)
+
var cluster cnpgv1.Cluster
var barmanObjectStore barmancloudv1.ObjectStore
@@ -88,7 +90,17 @@ func (c *CatalogMaintenanceRunnable) cycle(ctx context.Context) (time.Duration,
return 0, err
}
+ enabledPlugins := cnpgv1.GetPluginConfigurationEnabledPluginNames(cluster.Spec.Plugins)
+ if !slices.Contains(enabledPlugins, metadata.PluginName) {
+ contextLogger.Debug("Skipping maintenance cycle: plugin is not enabled for backups")
+ return 0, nil
+ }
+
configuration := config.NewFromCluster(&cluster)
+ if configuration == nil || len(configuration.BarmanObjectName) == 0 {
+ return 0, fmt.Errorf("invalid configuration, missing barman object store reference")
+ }
+
if err := c.Client.Get(ctx, configuration.GetBarmanObjectKey(), &barmanObjectStore); err != nil {
return 0, err
}
diff --git a/internal/cnpgi/metadata/constants.go b/internal/cnpgi/metadata/constants.go
index dad413a..fb45da6 100644
--- a/internal/cnpgi/metadata/constants.go
+++ b/internal/cnpgi/metadata/constants.go
@@ -26,6 +26,26 @@ import "github.com/cloudnative-pg/cnpg-i/pkg/identity"
const PluginName = "barman-cloud.cloudnative-pg.io"
const (
+ // ClusterLabelName is the label applied to RBAC resources created
+ // by this plugin. Its value is the name of the owning Cluster.
+ //
+ // Discovery contract: internal/controller/objectstore_controller.go
+ // selects Roles by this key when an ObjectStore is reconciled.
+ // Renaming or removing the label would break that controller; new
+ // recommended-label keys are added alongside it, never in place
+ // of it.
+ ClusterLabelName = "barmancloud.cnpg.io/cluster"
+
+ // AppLabelValue is the value applied to app.kubernetes.io/name on
+ // every plugin-managed object. It identifies the application as
+ // the Barman Cloud plugin (see issue #545).
+ AppLabelValue = "barman-cloud-plugin"
+
+ // ManagedByLabelValue is the value applied to app.kubernetes.io/managed-by
+ // on every plugin-managed object. It identifies this plugin as
+ // the controller responsible for the object.
+ ManagedByLabelValue = "plugin-barman-cloud"
+
// CheckEmptyWalArchiveFile is the name of the file in the PGDATA that,
// if present, requires the WAL archiver to check that the backup object
// store is empty.
@@ -43,7 +63,7 @@ const (
// Data is the metadata of this plugin.
var Data = identity.GetPluginMetadataResponse{
Name: PluginName,
- Version: "0.11.0", // x-release-please-version
+ Version: "0.12.0", // x-release-please-version
DisplayName: "BarmanCloudInstance",
ProjectUrl: "https://github.com/cloudnative-pg/plugin-barman-cloud",
RepositoryUrl: "https://github.com/cloudnative-pg/plugin-barman-cloud",
diff --git a/internal/cnpgi/operator/identity.go b/internal/cnpgi/operator/identity.go
index 0d48a19..8e6ee13 100644
--- a/internal/cnpgi/operator/identity.go
+++ b/internal/cnpgi/operator/identity.go
@@ -62,6 +62,13 @@ func (i IdentityImplementation) GetPluginCapabilities(
},
},
},
+ {
+ Type: &identity.PluginCapability_Service_{
+ Service: &identity.PluginCapability_Service{
+ Type: identity.PluginCapability_Service_TYPE_INSTANCE_SIDECAR_INJECTION,
+ },
+ },
+ },
},
}, nil
}
diff --git a/internal/cnpgi/operator/lifecycle.go b/internal/cnpgi/operator/lifecycle.go
index 8a0bbb5..b25af55 100644
--- a/internal/cnpgi/operator/lifecycle.go
+++ b/internal/cnpgi/operator/lifecycle.go
@@ -41,6 +41,9 @@ import (
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
)
+// fullRecoveryJobName is the name of the restore job.
+const fullRecoveryJobName = "full-recovery"
+
// LifecycleImplementation is the implementation of the lifecycle handler
type LifecycleImplementation struct {
lifecycle.UnimplementedOperatorLifecycleServer
@@ -48,6 +51,8 @@ type LifecycleImplementation struct {
}
// GetCapabilities exposes the lifecycle capabilities
+//
+//nolint:goconst
func (impl LifecycleImplementation) GetCapabilities(
_ context.Context,
_ *lifecycle.OperatorLifecycleCapabilitiesRequest,
@@ -186,7 +191,7 @@ func reconcileJob(
contextLogger.Debug("starting job reconciliation")
jobRole := getCNPGJobRole(&job)
- if jobRole != "full-recovery" &&
+ if jobRole != fullRecoveryJobName &&
jobRole != "snapshot-recovery" {
contextLogger.Debug("job is not a recovery job, skipping")
return nil, nil
diff --git a/internal/cnpgi/operator/lifecycle_test.go b/internal/cnpgi/operator/lifecycle_test.go
index 9d70a84..d2755ed 100644
--- a/internal/cnpgi/operator/lifecycle_test.go
+++ b/internal/cnpgi/operator/lifecycle_test.go
@@ -55,7 +55,7 @@ var _ = Describe("LifecycleImplementation", func() {
// helper to build a fake client with our scheme and optional objects
buildClientFunc := func(objs ...runtime.Object) *fake.ClientBuilder {
s := runtime.NewScheme()
- _ = barmancloudv1.AddToScheme(s)
+ barmancloudv1.AddKnownTypes(s)
return fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...)
}
@@ -139,10 +139,10 @@ var _ = Describe("LifecycleImplementation", func() {
Spec: batchv1.JobSpec{Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
- utils.JobRoleLabelName: "full-recovery",
+ utils.JobRoleLabelName: fullRecoveryJobName,
},
},
- Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "full-recovery"}}},
+ Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: fullRecoveryJobName}}},
}},
}
jobJSON, _ := json.Marshal(job)
@@ -351,7 +351,7 @@ var _ = Describe("LifecycleImplementation", func() {
},
}
s := runtime.NewScheme()
- _ = barmancloudv1.AddToScheme(s)
+ barmancloudv1.AddKnownTypes(s)
cli := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(store).Build()
impl := LifecycleImplementation{Client: cli}
@@ -378,7 +378,7 @@ var _ = Describe("LifecycleImplementation", func() {
},
}
s := runtime.NewScheme()
- _ = barmancloudv1.AddToScheme(s)
+ barmancloudv1.AddKnownTypes(s)
cli := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(store).Build()
impl := LifecycleImplementation{Client: cli}
diff --git a/internal/cnpgi/operator/manager.go b/internal/cnpgi/operator/manager.go
index 94dfa72..d6daf0a 100644
--- a/internal/cnpgi/operator/manager.go
+++ b/internal/cnpgi/operator/manager.go
@@ -24,7 +24,6 @@ import (
"crypto/tls"
// +kubebuilder:scaffold:imports
- cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/machinery/pkg/log"
"github.com/spf13/viper"
"k8s.io/apimachinery/pkg/runtime"
@@ -48,8 +47,7 @@ var scheme = runtime.NewScheme()
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
- utilruntime.Must(barmancloudv1.AddToScheme(scheme))
- utilruntime.Must(cnpgv1.AddToScheme(scheme))
+ barmancloudv1.AddKnownTypes(scheme)
// +kubebuilder:scaffold:scheme
}
diff --git a/internal/cnpgi/operator/rbac/doc.go b/internal/cnpgi/operator/rbac/doc.go
new file mode 100644
index 0000000..802e058
--- /dev/null
+++ b/internal/cnpgi/operator/rbac/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+// Package rbac contains utilities to reconcile RBAC resources
+// for the barman-cloud plugin.
+package rbac
diff --git a/internal/cnpgi/operator/rbac/ensure.go b/internal/cnpgi/operator/rbac/ensure.go
new file mode 100644
index 0000000..2422080
--- /dev/null
+++ b/internal/cnpgi/operator/rbac/ensure.go
@@ -0,0 +1,369 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package rbac
+
+import (
+ "context"
+ "fmt"
+
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ "github.com/cloudnative-pg/machinery/pkg/log"
+ rbacv1 "k8s.io/api/rbac/v1"
+ "k8s.io/apimachinery/pkg/api/equality"
+ apierrs "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/client-go/util/retry"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
+)
+
+// EnsureRole ensures the RBAC Role for the given Cluster matches
+// the desired state derived from the given ObjectStores. On creation,
+// the Cluster is set as the owner of the Role for garbage collection.
+//
+// This function is called from the Pre hook (gRPC). It creates the
+// Role if it does not exist, then patches rules and labels to match
+// the desired state.
+//
+// Note: the ObjectStore controller (EnsureRoleRules) can patch the
+// same Role concurrently. Both paths use RetryOnConflict but compute
+// desired rules from their own view of ObjectStores. If the Pre hook
+// reads stale ObjectStore data from the informer cache, it may
+// briefly revert a fresher update. This is self-healing: the next
+// ObjectStore reconcile restores the correct state.
+func EnsureRole(
+ ctx context.Context,
+ c client.Client,
+ cluster *cnpgv1.Cluster,
+ barmanObjects []barmancloudv1.ObjectStore,
+) error {
+ newRole := specs.BuildRole(cluster, barmanObjects)
+ roleKey := client.ObjectKeyFromObject(newRole)
+
+ if err := ensureRoleExists(ctx, c, cluster, newRole); err != nil {
+ return err
+ }
+
+ return patchRole(ctx, c, roleKey, newRole.Rules, specs.BuildLabels(cluster))
+}
+
+// EnsureRoleRules updates the rules of an existing Role to match
+// the desired state derived from the given ObjectStores. Unlike
+// EnsureRole, this function does not create Roles or set owner
+// references — it only patches rules on Roles that already exist.
+// It is intended for the ObjectStore controller path where no
+// Cluster object is available. Returns nil if the Role does not
+// exist (the Pre hook has not created it yet).
+func EnsureRoleRules(
+ ctx context.Context,
+ c client.Client,
+ roleKey client.ObjectKey,
+ barmanObjects []barmancloudv1.ObjectStore,
+) error {
+ err := patchRole(ctx, c, roleKey, specs.BuildRoleRules(barmanObjects), nil)
+ if apierrs.IsNotFound(err) {
+ log.FromContext(ctx).Debug("Role not found, skipping rule update",
+ "name", roleKey.Name, "namespace", roleKey.Namespace)
+ return nil
+ }
+
+ return err
+}
+
+// EnsureRoleBinding ensures the RoleBinding for the given Cluster
+// is present and carries the recommended labels.
+//
+// This function is called from the Pre hook (gRPC). It creates the
+// RoleBinding if it does not exist, then reconciles labels and
+// Subjects:
+// - Labels are written per-key. Keys the plugin manages overwrite
+// existing values; unrelated keys (anything outside the desired
+// set) are left alone.
+// - Subjects are additive. The plugin guarantees its own Subject
+// is bound, but never removes Subjects added by other actors —
+// a Subject is a grant of access, and silently revoking access
+// someone else granted is the wrong default.
+//
+// RoleRef is immutable in Kubernetes. If the existing RoleBinding
+// points to a different Role, the plugin fails loudly so the
+// operator notices and recreates the object.
+func EnsureRoleBinding(ctx context.Context, c client.Client, cluster *cnpgv1.Cluster) error {
+ desiredRoleBinding := specs.BuildRoleBinding(cluster)
+ if err := specs.SetControllerReference(cluster, desiredRoleBinding); err != nil {
+ return err
+ }
+
+ roleBinding, err := getOrCreateRoleBinding(ctx, c, desiredRoleBinding)
+ if err != nil || roleBinding == nil {
+ // Either an error, or we just created the object with the
+ // desired state — nothing to patch.
+ return err
+ }
+
+ return reconcileRoleBinding(ctx, c, roleBinding, desiredRoleBinding)
+}
+
+// getOrCreateRoleBinding returns the existing RoleBinding when it
+// is already present on the API server, or nil after a successful
+// Create when the just-created object already carries the desired
+// state (so the caller can skip the patch path).
+//
+// On a stale-informer-cache race during plugin pod startup, where
+// Get returns NotFound but Create returns AlreadyExists, the
+// function re-Gets to return the racing winner — the caller then
+// falls through to reconciliation against that real object.
+func getOrCreateRoleBinding(
+ ctx context.Context,
+ c client.Client,
+ desired *rbacv1.RoleBinding,
+) (*rbacv1.RoleBinding, error) {
+ contextLogger := log.FromContext(ctx)
+
+ rb := &rbacv1.RoleBinding{}
+ err := c.Get(ctx, client.ObjectKeyFromObject(desired), rb)
+ if err == nil {
+ return rb, nil
+ }
+ if !apierrs.IsNotFound(err) {
+ return nil, err
+ }
+
+ createErr := c.Create(ctx, desired)
+ switch {
+ case createErr == nil:
+ contextLogger.Info("Created RoleBinding",
+ "name", desired.Name, "namespace", desired.Namespace)
+ // Just-created with the desired state — caller skips patch.
+ return nil, nil
+ case apierrs.IsAlreadyExists(createErr):
+ contextLogger.Debug(
+ "RoleBinding already exists, likely a stale informer cache; re-fetching",
+ "name", desired.Name, "namespace", desired.Namespace)
+ // Re-Get to return the racing winner so the caller can
+ // reconcile against the real existing object.
+ fetched := &rbacv1.RoleBinding{}
+ if err := c.Get(ctx, client.ObjectKeyFromObject(desired), fetched); err != nil {
+ return nil, err
+ }
+ return fetched, nil
+ default:
+ return nil, createErr
+ }
+}
+
+// reconcileRoleBinding brings an existing RoleBinding's labels and
+// Subjects into alignment with desired. It re-Gets the object on
+// conflict-retry so each attempt observes fresh server state, and
+// uses optimistic locking so a competing writer's patch is rejected
+// with 409 instead of silently last-write-winning.
+//
+// On the first attempt the function uses the existing object passed
+// in by the caller, avoiding a second Get on the steady-state path.
+func reconcileRoleBinding(
+ ctx context.Context,
+ c client.Client,
+ existing, desired *rbacv1.RoleBinding,
+) error {
+ contextLogger := log.FromContext(ctx)
+ first := true
+ return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
+ var roleBinding *rbacv1.RoleBinding
+ if first {
+ roleBinding = existing
+ first = false
+ } else {
+ roleBinding = &rbacv1.RoleBinding{}
+ if err := c.Get(ctx, client.ObjectKeyFromObject(desired), roleBinding); err != nil {
+ return err
+ }
+ }
+
+ // RoleRef is immutable in Kubernetes; we cannot patch it.
+ // Divergence at the canonical name is corruption regardless
+ // of who wrote the existing object — fail loudly so the
+ // operator notices and deletes the RoleBinding, and the
+ // next Pre call recreates it correctly.
+ if !equality.Semantic.DeepEqual(roleBinding.RoleRef, desired.RoleRef) {
+ return fmt.Errorf(
+ "RoleBinding %s/%s has divergent immutable RoleRef "+
+ "(existing=%+v, desired=%+v); delete the RoleBinding to allow recreation",
+ roleBinding.Namespace, roleBinding.Name,
+ roleBinding.RoleRef, desired.RoleRef)
+ }
+
+ if !roleBindingNeedsUpdate(roleBinding, desired) {
+ return nil
+ }
+
+ contextLogger.Info("Patching role binding",
+ "name", roleBinding.Name, "namespace", roleBinding.Namespace)
+
+ oldRoleBinding := roleBinding.DeepCopy()
+ roleBinding.Labels = mergeLabels(roleBinding.Labels, desired.Labels)
+ roleBinding.Subjects = mergeSubjects(roleBinding.Subjects, desired.Subjects)
+
+ return c.Patch(ctx, roleBinding,
+ client.MergeFromWithOptions(oldRoleBinding, client.MergeFromWithOptimisticLock{}))
+ })
+}
+
+// ensureRoleExists creates the Role if it does not exist. Returns
+// nil on success and nil on AlreadyExists (another writer created
+// it concurrently). The caller always follows up with patchRole.
+func ensureRoleExists(
+ ctx context.Context,
+ c client.Client,
+ cluster *cnpgv1.Cluster,
+ newRole *rbacv1.Role,
+) error {
+ contextLogger := log.FromContext(ctx)
+
+ var existing rbacv1.Role
+ err := c.Get(ctx, client.ObjectKeyFromObject(newRole), &existing)
+ if err == nil {
+ return nil
+ }
+ if !apierrs.IsNotFound(err) {
+ return err
+ }
+
+ if err := specs.SetControllerReference(cluster, newRole); err != nil {
+ return err
+ }
+
+ contextLogger.Info("Creating role",
+ "name", newRole.Name, "namespace", newRole.Namespace)
+
+ createErr := c.Create(ctx, newRole)
+ if createErr == nil || apierrs.IsAlreadyExists(createErr) {
+ return nil
+ }
+
+ return createErr
+}
+
+// patchRole patches the Role's rules and optionally its labels to
+// match the desired state. When desiredLabels is nil, labels are
+// not modified. Uses retry.RetryOnConflict for concurrent
+// modification handling.
+func patchRole(
+ ctx context.Context,
+ c client.Client,
+ roleKey client.ObjectKey,
+ desiredRules []rbacv1.PolicyRule,
+ desiredLabels map[string]string,
+) error {
+ return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
+ var role rbacv1.Role
+ if err := c.Get(ctx, roleKey, &role); err != nil {
+ return err
+ }
+
+ rulesMatch := equality.Semantic.DeepEqual(desiredRules, role.Rules)
+ labelsMatch := desiredLabels == nil || !labelsNeedUpdate(role.Labels, desiredLabels)
+
+ if rulesMatch && labelsMatch {
+ return nil
+ }
+
+ contextLogger := log.FromContext(ctx)
+ contextLogger.Info("Patching role",
+ "name", role.Name, "namespace", role.Namespace)
+
+ oldRole := role.DeepCopy()
+ role.Rules = desiredRules
+ role.Labels = mergeLabels(role.Labels, desiredLabels)
+
+ return c.Patch(ctx, &role,
+ client.MergeFromWithOptions(oldRole, client.MergeFromWithOptimisticLock{}))
+ })
+}
+
+// mergeLabels writes the desired labels onto existing per-key.
+// Keys in desired overwrite the existing value; keys not in desired
+// (any unrelated label a user may have set) are left alone.
+func mergeLabels(existing, desired map[string]string) map[string]string {
+ if len(desired) == 0 {
+ return existing
+ }
+ if existing == nil {
+ existing = make(map[string]string, len(desired))
+ }
+ for k, v := range desired {
+ existing[k] = v
+ }
+ return existing
+}
+
+// labelsNeedUpdate returns true if a Patch is required to bring
+// existing labels into the state mergeLabels would produce, i.e.
+// any desired key is missing or has a different value in existing.
+func labelsNeedUpdate(existing, desired map[string]string) bool {
+ for k, v := range desired {
+ if existing[k] != v {
+ return true
+ }
+ }
+ return false
+}
+
+// containsSubject reports whether subjects contains an element that
+// is semantically equal to subject.
+func containsSubject(subjects []rbacv1.Subject, subject rbacv1.Subject) bool {
+ for _, s := range subjects {
+ if equality.Semantic.DeepEqual(s, subject) {
+ return true
+ }
+ }
+ return false
+}
+
+// mergeSubjects appends desired Subjects that are not already
+// present in existing.
+//
+// This is intentionally asymmetric to mergeLabels: labels are
+// metadata, so replacing stale plugin-set values is safe. A
+// Subject is a grant of access, so removing a Subject silently
+// revokes permissions an external operator chose to grant. The
+// plugin only requires that ITS Subject is present, not that it
+// is exclusive.
+func mergeSubjects(existing, desired []rbacv1.Subject) []rbacv1.Subject {
+ for _, d := range desired {
+ if !containsSubject(existing, d) {
+ existing = append(existing, d)
+ }
+ }
+ return existing
+}
+
+// roleBindingNeedsUpdate returns true if a Patch is required to
+// bring existing into alignment with desired — any desired Subject
+// missing (see mergeSubjects), or any desired label key missing
+// or holding a stale value (see mergeLabels).
+func roleBindingNeedsUpdate(existing, desired *rbacv1.RoleBinding) bool {
+ for _, s := range desired.Subjects {
+ if !containsSubject(existing.Subjects, s) {
+ return true
+ }
+ }
+
+ return labelsNeedUpdate(existing.Labels, desired.Labels)
+}
diff --git a/internal/cnpgi/operator/rbac/ensure_test.go b/internal/cnpgi/operator/rbac/ensure_test.go
new file mode 100644
index 0000000..238ca0a
--- /dev/null
+++ b/internal/cnpgi/operator/rbac/ensure_test.go
@@ -0,0 +1,752 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package rbac_test
+
+import (
+ "context"
+ "fmt"
+
+ barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ "github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
+ machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ rbacv1 "k8s.io/api/rbac/v1"
+ apierrs "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
+ "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
+
+ barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
+)
+
+func expectRequiredLabels(labels map[string]string, clusterName string) {
+ ExpectWithOffset(1, labels).To(HaveKeyWithValue(metadata.ClusterLabelName, clusterName))
+ ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppLabelName, metadata.AppLabelValue))
+ ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppInstanceLabelName, clusterName))
+ ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppManagedByLabelName, metadata.ManagedByLabelValue))
+ ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppComponentLabelName, utils.DatabaseComponentName))
+ ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppVersionLabelName, metadata.Data.Version))
+}
+
+// newPatchCountingClient returns a fake client plus a pointer to a
+// counter incremented on every Patch call. Useful for asserting
+// that a "no-op" reconcile path issues no Patch — more reliable
+// than comparing ResourceVersion across reads, which depends on
+// fake-client RV-bumping semantics that are not part of the
+// controller-runtime contract.
+func newPatchCountingClient(initObjs ...client.Object) (client.Client, *int) {
+ count := 0
+ c := fake.NewClientBuilder().
+ WithScheme(newScheme()).
+ WithObjects(initObjs...).
+ WithInterceptorFuncs(interceptor.Funcs{
+ Patch: func(
+ ctx context.Context,
+ client client.WithWatch,
+ obj client.Object,
+ patch client.Patch,
+ opts ...client.PatchOption,
+ ) error {
+ count++
+ return client.Patch(ctx, obj, patch, opts...)
+ },
+ }).
+ Build()
+ return c, &count
+}
+
+func newScheme() *runtime.Scheme {
+ s := runtime.NewScheme()
+ utilruntime.Must(rbacv1.AddToScheme(s))
+ utilruntime.Must(cnpgv1.AddToScheme(s))
+ barmancloudv1.AddKnownTypes(s)
+ return s
+}
+
+func newCluster(name, namespace string) *cnpgv1.Cluster {
+ return &cnpgv1.Cluster{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: cnpgv1.SchemeGroupVersion.String(),
+ Kind: cnpgv1.ClusterKind,
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: namespace,
+ },
+ }
+}
+
+func newObjectStore(name, namespace, secretName string) barmancloudv1.ObjectStore {
+ return barmancloudv1.ObjectStore{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: namespace,
+ },
+ Spec: barmancloudv1.ObjectStoreSpec{
+ Configuration: barmanapi.BarmanObjectStoreConfiguration{
+ DestinationPath: "s3://bucket/path",
+ BarmanCredentials: barmanapi.BarmanCredentials{
+ AWS: &barmanapi.S3Credentials{
+ AccessKeyIDReference: &machineryapi.SecretKeySelector{
+ LocalObjectReference: machineryapi.LocalObjectReference{
+ Name: secretName,
+ },
+ Key: "ACCESS_KEY_ID",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+var _ = Describe("EnsureRole", func() {
+ var (
+ ctx context.Context
+ cluster *cnpgv1.Cluster
+ objects []barmancloudv1.ObjectStore
+ fakeClient client.Client
+ )
+
+ BeforeEach(func() {
+ ctx = context.Background()
+ cluster = newCluster("test-cluster", "default")
+ objects = []barmancloudv1.ObjectStore{
+ newObjectStore("my-store", "default", "aws-creds"),
+ }
+ })
+
+ Context("when the Role does not exist", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ })
+
+ It("should create the Role with owner reference and label", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).NotTo(HaveOccurred())
+
+ var role rbacv1.Role
+ err = fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &role)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(role.Rules).To(HaveLen(3))
+
+ Expect(role.OwnerReferences).To(HaveLen(1))
+ Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
+ Expect(role.OwnerReferences[0].Kind).To(Equal("Cluster"))
+
+ expectRequiredLabels(role.Labels, "test-cluster")
+ })
+ })
+
+ Context("when the Role exists with matching rules", func() {
+ var patchCount *int
+
+ BeforeEach(func() {
+ fakeClient, patchCount = newPatchCountingClient()
+ Expect(rbac.EnsureRole(ctx, fakeClient, cluster, objects)).To(Succeed())
+ *patchCount = 0
+ })
+
+ It("should not patch the Role", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(*patchCount).To(BeZero())
+ })
+ })
+
+ Context("when the Role exists with different rules", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ oldObjects := []barmancloudv1.ObjectStore{
+ newObjectStore("my-store", "default", "old-secret"),
+ }
+ Expect(rbac.EnsureRole(ctx, fakeClient, cluster, oldObjects)).To(Succeed())
+ })
+
+ It("should patch the Role with new rules and preserve owner reference", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).NotTo(HaveOccurred())
+
+ var role rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &role)).To(Succeed())
+
+ secretsRule := role.Rules[2]
+ Expect(secretsRule.ResourceNames).To(ContainElement("aws-creds"))
+ Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
+
+ Expect(role.OwnerReferences).To(HaveLen(1))
+ Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
+ })
+ })
+
+ Context("when Role creation fails with a transient error", func() {
+ BeforeEach(func() {
+ internalErr := apierrs.NewInternalError(fmt.Errorf("etcd timeout"))
+ fakeClient = fake.NewClientBuilder().
+ WithScheme(newScheme()).
+ WithInterceptorFuncs(interceptor.Funcs{
+ Create: func(ctx context.Context, c client.WithWatch, obj client.Object, opts ...client.CreateOption) error {
+ return internalErr
+ },
+ }).
+ Build()
+ })
+
+ It("should propagate the error", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).To(HaveOccurred())
+ Expect(apierrs.IsInternalError(err)).To(BeTrue())
+ })
+ })
+
+ Context("when the Role has pre-existing unrelated labels", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.Role{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ Labels: map[string]string{
+ "custom-label": "custom-value",
+ },
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should preserve unrelated labels while adding the cluster label", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).NotTo(HaveOccurred())
+
+ var role rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &role)).To(Succeed())
+
+ Expect(role.Labels).To(HaveKeyWithValue("custom-label", "custom-value"))
+ expectRequiredLabels(role.Labels, "test-cluster")
+ })
+ })
+
+ Context("when the Role exists with a stale label value", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.Role{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ Labels: map[string]string{
+ // Stale value as if written by an older plugin
+ // version.
+ utils.KubernetesAppVersionLabelName: "0.0.0-stale",
+ },
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should overwrite the stale value with the current plugin's value", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).NotTo(HaveOccurred())
+
+ var role rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &role)).To(Succeed())
+
+ Expect(role.Labels).To(HaveKeyWithValue(
+ utils.KubernetesAppVersionLabelName, metadata.Data.Version))
+ })
+ })
+
+ Context("when the Role exists without the cluster label (upgrade scenario)", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+
+ // Create a Role without the label (simulates pre-upgrade state)
+ unlabeledRole := &rbacv1.Role{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ },
+ Rules: []rbacv1.PolicyRule{},
+ }
+ Expect(fakeClient.Create(ctx, unlabeledRole)).To(Succeed())
+ })
+
+ It("should add the label and update rules", func() {
+ err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
+ Expect(err).NotTo(HaveOccurred())
+
+ var role rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &role)).To(Succeed())
+
+ expectRequiredLabels(role.Labels, "test-cluster")
+ Expect(role.Rules).To(HaveLen(3))
+ })
+ })
+})
+
+var _ = Describe("EnsureRoleBinding", func() {
+ var (
+ ctx context.Context
+ cluster *cnpgv1.Cluster
+ fakeClient client.Client
+ )
+
+ BeforeEach(func() {
+ ctx = context.Background()
+ cluster = newCluster("test-cluster", "default")
+ })
+
+ Context("when the RoleBinding does not exist", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ })
+
+ It("should create the RoleBinding with owner reference, labels, and correct subjects", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+
+ var rb rbacv1.RoleBinding
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &rb)).To(Succeed())
+
+ Expect(rb.OwnerReferences).To(HaveLen(1))
+ Expect(rb.OwnerReferences[0].Name).To(Equal("test-cluster"))
+ Expect(rb.OwnerReferences[0].Kind).To(Equal("Cluster"))
+
+ expectRequiredLabels(rb.Labels, "test-cluster")
+
+ Expect(rb.Subjects).To(HaveLen(1))
+ Expect(rb.Subjects[0].Name).To(Equal("test-cluster"))
+ Expect(rb.Subjects[0].Kind).To(Equal("ServiceAccount"))
+
+ Expect(rb.RoleRef.Kind).To(Equal("Role"))
+ Expect(rb.RoleRef.Name).To(Equal("test-cluster-barman-cloud"))
+ })
+ })
+
+ Context("when the RoleBinding exists with matching state", func() {
+ var patchCount *int
+
+ BeforeEach(func() {
+ fakeClient, patchCount = newPatchCountingClient()
+ Expect(rbac.EnsureRoleBinding(ctx, fakeClient, cluster)).To(Succeed())
+ *patchCount = 0
+ })
+
+ It("should not patch the RoleBinding", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(*patchCount).To(BeZero())
+ })
+ })
+
+ Context("when the RoleBinding exists with extra user-added subjects", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ },
+ Subjects: []rbacv1.Subject{
+ {
+ Kind: "ServiceAccount",
+ Name: "user-debug-sa",
+ APIGroup: "",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "test-cluster-barman-cloud",
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should add the plugin's subject without removing user-added ones", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+
+ var rb rbacv1.RoleBinding
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &rb)).To(Succeed())
+
+ // Additive policy: the user-added subject must remain.
+ Expect(rb.Subjects).To(ContainElement(rbacv1.Subject{
+ Kind: "ServiceAccount",
+ Name: "user-debug-sa",
+ APIGroup: "",
+ }))
+ // The plugin's required subject must be present.
+ Expect(rb.Subjects).To(ContainElement(rbacv1.Subject{
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ }))
+ })
+ })
+
+ Context("when the RoleBinding exists with a stale label value", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ Labels: map[string]string{
+ utils.KubernetesAppVersionLabelName: "0.0.0-stale",
+ },
+ },
+ Subjects: []rbacv1.Subject{
+ {
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "test-cluster-barman-cloud",
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should overwrite the stale value with the current plugin's value", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+
+ var rb rbacv1.RoleBinding
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &rb)).To(Succeed())
+
+ Expect(rb.Labels).To(HaveKeyWithValue(
+ utils.KubernetesAppVersionLabelName, metadata.Data.Version))
+ })
+ })
+
+ Context("when the RoleBinding has pre-existing unrelated labels", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ Labels: map[string]string{
+ "custom-label": "custom-value",
+ },
+ },
+ Subjects: []rbacv1.Subject{
+ {
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "test-cluster-barman-cloud",
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should preserve unrelated labels while adding the required labels", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+
+ var rb rbacv1.RoleBinding
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &rb)).To(Succeed())
+
+ Expect(rb.Labels).To(HaveKeyWithValue("custom-label", "custom-value"))
+ expectRequiredLabels(rb.Labels, "test-cluster")
+ })
+ })
+
+ Context("when the RoleBinding has a divergent RoleRef", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ },
+ Subjects: []rbacv1.Subject{
+ {
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "wrong-role",
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should return a descriptive error since RoleRef is immutable", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("RoleRef"))
+ Expect(err.Error()).To(ContainSubstring("wrong-role"))
+ })
+ })
+
+ Context("when an AlreadyExists race happens during a stale-cache create (plugin pod startup)", func() {
+ var preExisting *rbacv1.RoleBinding
+
+ BeforeEach(func() {
+ preExisting = &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ },
+ Subjects: []rbacv1.Subject{
+ {
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "test-cluster-barman-cloud",
+ },
+ }
+
+ // First Get returns NotFound (simulates cold informer
+ // cache after plugin pod restart). Subsequent Gets
+ // fall through to real fake-client behavior.
+ gets := 0
+ fakeClient = fake.NewClientBuilder().
+ WithScheme(newScheme()).
+ WithObjects(preExisting).
+ WithInterceptorFuncs(interceptor.Funcs{
+ Get: func(
+ ctx context.Context,
+ c client.WithWatch,
+ key client.ObjectKey,
+ obj client.Object,
+ opts ...client.GetOption,
+ ) error {
+ gets++
+ if gets == 1 {
+ return apierrs.NewNotFound(
+ rbacv1.Resource("rolebindings"), key.Name)
+ }
+ return c.Get(ctx, key, obj, opts...)
+ },
+ }).
+ Build()
+ })
+
+ It("should tolerate the AlreadyExists and reconcile from the existing object", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+
+ var rb rbacv1.RoleBinding
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &rb)).To(Succeed())
+
+ Expect(rb.Subjects).To(ContainElement(rbacv1.Subject{
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ }))
+ })
+ })
+
+ Context("when the RoleBinding exists without labels (upgrade scenario)", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ existing := &rbacv1.RoleBinding{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-cluster-barman-cloud",
+ Namespace: "default",
+ },
+ Subjects: []rbacv1.Subject{
+ {
+ Kind: "ServiceAccount",
+ Name: "test-cluster",
+ Namespace: "default",
+ APIGroup: "",
+ },
+ },
+ RoleRef: rbacv1.RoleRef{
+ APIGroup: "rbac.authorization.k8s.io",
+ Kind: "Role",
+ Name: "test-cluster-barman-cloud",
+ },
+ }
+ Expect(fakeClient.Create(ctx, existing)).To(Succeed())
+ })
+
+ It("should add the required labels", func() {
+ err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
+ Expect(err).NotTo(HaveOccurred())
+
+ var rb rbacv1.RoleBinding
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }, &rb)).To(Succeed())
+
+ expectRequiredLabels(rb.Labels, "test-cluster")
+ })
+ })
+})
+
+var _ = Describe("EnsureRoleRules", func() {
+ var (
+ ctx context.Context
+ fakeClient client.Client
+ objects []barmancloudv1.ObjectStore
+ )
+
+ BeforeEach(func() {
+ ctx = context.Background()
+ objects = []barmancloudv1.ObjectStore{
+ newObjectStore("my-store", "default", "aws-creds"),
+ }
+ })
+
+ Context("when the Role exists", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+
+ // Seed a labeled Role with old rules
+ cluster := newCluster("test-cluster", "default")
+ oldObjects := []barmancloudv1.ObjectStore{
+ newObjectStore("my-store", "default", "old-secret"),
+ }
+ Expect(rbac.EnsureRole(ctx, fakeClient, cluster, oldObjects)).To(Succeed())
+ })
+
+ It("should patch the rules", func() {
+ roleKey := client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }
+ err := rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)
+ Expect(err).NotTo(HaveOccurred())
+
+ var role rbacv1.Role
+ Expect(fakeClient.Get(ctx, roleKey, &role)).To(Succeed())
+
+ secretsRule := role.Rules[2]
+ Expect(secretsRule.ResourceNames).To(ContainElement("aws-creds"))
+ Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
+ })
+
+ It("should not patch when rules already match", func() {
+ // Replace the seeded client with a counting one,
+ // then re-seed via EnsureRole so the desired rules
+ // are already in place when EnsureRoleRules runs.
+ var patchCount *int
+ fakeClient, patchCount = newPatchCountingClient()
+ cluster := newCluster("test-cluster", "default")
+ Expect(rbac.EnsureRole(ctx, fakeClient, cluster, objects)).To(Succeed())
+ *patchCount = 0
+
+ roleKey := client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }
+ Expect(rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)).To(Succeed())
+ Expect(*patchCount).To(BeZero())
+ })
+
+ It("should not modify labels", func() {
+ roleKey := client.ObjectKey{
+ Namespace: "default",
+ Name: "test-cluster-barman-cloud",
+ }
+
+ var before rbacv1.Role
+ Expect(fakeClient.Get(ctx, roleKey, &before)).To(Succeed())
+
+ Expect(rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)).To(Succeed())
+
+ var after rbacv1.Role
+ Expect(fakeClient.Get(ctx, roleKey, &after)).To(Succeed())
+ Expect(after.Labels).To(Equal(before.Labels))
+ })
+ })
+
+ Context("when the Role does not exist", func() {
+ BeforeEach(func() {
+ fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
+ })
+
+ It("should return nil", func() {
+ roleKey := client.ObjectKey{
+ Namespace: "default",
+ Name: "nonexistent-barman-cloud",
+ }
+ err := rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)
+ Expect(err).NotTo(HaveOccurred())
+ })
+ })
+})
diff --git a/internal/cnpgi/operator/rbac/suite_test.go b/internal/cnpgi/operator/rbac/suite_test.go
new file mode 100644
index 0000000..42fedae
--- /dev/null
+++ b/internal/cnpgi/operator/rbac/suite_test.go
@@ -0,0 +1,32 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package rbac_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestRBAC(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "RBAC Suite")
+}
diff --git a/internal/cnpgi/operator/reconciler.go b/internal/cnpgi/operator/reconciler.go
index 9d64deb..dd92dd8 100644
--- a/internal/cnpgi/operator/reconciler.go
+++ b/internal/cnpgi/operator/reconciler.go
@@ -27,14 +27,12 @@ import (
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/object"
"github.com/cloudnative-pg/cnpg-i/pkg/reconciler"
"github.com/cloudnative-pg/machinery/pkg/log"
- rbacv1 "k8s.io/api/rbac/v1"
- "k8s.io/apimachinery/pkg/api/equality"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
- "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
)
// ReconcilerImplementation implements the Reconciler capability
@@ -113,11 +111,11 @@ func (r ReconcilerImplementation) Pre(
barmanObjects = append(barmanObjects, barmanObject)
}
- if err := r.ensureRole(ctx, &cluster, barmanObjects); err != nil {
+ if err := rbac.EnsureRole(ctx, r.Client, &cluster, barmanObjects); err != nil {
return nil, err
}
- if err := r.ensureRoleBinding(ctx, &cluster); err != nil {
+ if err := rbac.EnsureRoleBinding(ctx, r.Client, &cluster); err != nil {
return nil, err
}
@@ -136,85 +134,3 @@ func (r ReconcilerImplementation) Post(
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_CONTINUE,
}, nil
}
-
-func (r ReconcilerImplementation) ensureRole(
- ctx context.Context,
- cluster *cnpgv1.Cluster,
- barmanObjects []barmancloudv1.ObjectStore,
-) error {
- contextLogger := log.FromContext(ctx)
- newRole := specs.BuildRole(cluster, barmanObjects)
-
- var role rbacv1.Role
- if err := r.Client.Get(ctx, client.ObjectKey{
- Namespace: newRole.Namespace,
- Name: newRole.Name,
- }, &role); err != nil {
- if !apierrs.IsNotFound(err) {
- return err
- }
-
- contextLogger.Info(
- "Creating role",
- "name", newRole.Name,
- "namespace", newRole.Namespace,
- )
-
- if err := setOwnerReference(cluster, newRole); err != nil {
- return err
- }
-
- return r.Client.Create(ctx, newRole)
- }
-
- if equality.Semantic.DeepEqual(newRole.Rules, role.Rules) {
- // There's no need to hit the API server again
- return nil
- }
-
- contextLogger.Info(
- "Patching role",
- "name", newRole.Name,
- "namespace", newRole.Namespace,
- "rules", newRole.Rules,
- )
-
- oldRole := role.DeepCopy()
-
- // Apply to the role the new rules
- role.Rules = newRole.Rules
-
- // Push it back to the API server
- return r.Client.Patch(ctx, &role, client.MergeFrom(oldRole))
-}
-
-func (r ReconcilerImplementation) ensureRoleBinding(
- ctx context.Context,
- cluster *cnpgv1.Cluster,
-) error {
- var role rbacv1.RoleBinding
- if err := r.Client.Get(ctx, client.ObjectKey{
- Namespace: cluster.Namespace,
- Name: specs.GetRBACName(cluster.Name),
- }, &role); err != nil {
- if apierrs.IsNotFound(err) {
- return r.createRoleBinding(ctx, cluster)
- }
- return err
- }
-
- // TODO: this assumes role bindings never change.
- // Is that true? Should we relax this assumption?
- return nil
-}
-
-func (r ReconcilerImplementation) createRoleBinding(
- ctx context.Context,
- cluster *cnpgv1.Cluster,
-) error {
- roleBinding := specs.BuildRoleBinding(cluster)
- if err := setOwnerReference(cluster, roleBinding); err != nil {
- return err
- }
- return r.Client.Create(ctx, roleBinding)
-}
diff --git a/internal/cnpgi/operator/specs/labels.go b/internal/cnpgi/operator/specs/labels.go
new file mode 100644
index 0000000..3d9042b
--- /dev/null
+++ b/internal/cnpgi/operator/specs/labels.go
@@ -0,0 +1,41 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package specs
+
+import (
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ "github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
+
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+)
+
+// BuildLabels returns the Kubernetes recommended labels applied to
+// every object managed by this plugin for the given Cluster. See
+// https://github.com/cloudnative-pg/plugin-barman-cloud/issues/545.
+func BuildLabels(cluster *cnpgv1.Cluster) map[string]string {
+ return map[string]string{
+ metadata.ClusterLabelName: cluster.Name,
+ utils.KubernetesAppLabelName: metadata.AppLabelValue,
+ utils.KubernetesAppInstanceLabelName: cluster.Name,
+ utils.KubernetesAppVersionLabelName: metadata.Data.Version,
+ utils.KubernetesAppComponentLabelName: utils.DatabaseComponentName,
+ utils.KubernetesAppManagedByLabelName: metadata.ManagedByLabelValue,
+ }
+}
diff --git a/internal/cnpgi/operator/specs/labels_test.go b/internal/cnpgi/operator/specs/labels_test.go
new file mode 100644
index 0000000..82fe8ae
--- /dev/null
+++ b/internal/cnpgi/operator/specs/labels_test.go
@@ -0,0 +1,68 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package specs
+
+import (
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ "github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+)
+
+var _ = Describe("BuildLabels", func() {
+ It("should return the recommended labels with plugin identity", func() {
+ cluster := &cnpgv1.Cluster{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-cluster",
+ Namespace: "default",
+ },
+ }
+ labels := BuildLabels(cluster)
+
+ Expect(labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "my-cluster"))
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppLabelName, metadata.AppLabelValue))
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppInstanceLabelName, "my-cluster"))
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppVersionLabelName, metadata.Data.Version))
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppComponentLabelName, utils.DatabaseComponentName))
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppManagedByLabelName, metadata.ManagedByLabelValue))
+ Expect(labels).To(HaveLen(6))
+ })
+
+ It("should report the plugin version regardless of the cluster's Postgres image", func() {
+ cluster := &cnpgv1.Cluster{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "pg16-cluster",
+ Namespace: "default",
+ },
+ Spec: cnpgv1.ClusterSpec{
+ ImageCatalogRef: &cnpgv1.ImageCatalogRef{
+ Major: 16,
+ },
+ },
+ }
+ labels := BuildLabels(cluster)
+
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppVersionLabelName, metadata.Data.Version))
+ Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppInstanceLabelName, "pg16-cluster"))
+ })
+})
diff --git a/internal/cnpgi/operator/ownership.go b/internal/cnpgi/operator/specs/ownership.go
similarity index 50%
rename from internal/cnpgi/operator/ownership.go
rename to internal/cnpgi/operator/specs/ownership.go
index e0aadcb..dded5d1 100644
--- a/internal/cnpgi/operator/ownership.go
+++ b/internal/cnpgi/operator/specs/ownership.go
@@ -17,7 +17,7 @@ limitations under the License.
SPDX-License-Identifier: Apache-2.0
*/
-package operator
+package specs
import (
"fmt"
@@ -27,26 +27,32 @@ import (
"k8s.io/utils/ptr"
)
-// setOwnerReference explicitly set the owner reference between an
-// owner object and a controller one.
+// SetControllerReference sets an owner reference on controlled
+// pointing to owner, reading the GVK from the owner object's
+// metadata rather than from a scheme. This is necessary because
+// the operator does not know the CNPG API group at compile time
+// (it may be customized), while the Cluster object decoded from
+// the gRPC request carries the correct GVK in its TypeMeta.
//
-// Important: this function won't use any registered scheme and will
-// fail unless the metadata has been correctly set into the owner
-// object.
-func setOwnerReference(owner, controlled metav1.Object) error {
+// This function replaces all existing owner references rather than
+// merging, so it assumes the controlled object has a single owner.
+// This holds for plugin-managed Roles and RoleBindings, which are
+// exclusively owned by one Cluster.
+func SetControllerReference(owner, controlled metav1.Object) error {
ro, ok := owner.(runtime.Object)
if !ok {
- return fmt.Errorf("%T is not a runtime.Object, cannot call setOwnerReference", owner)
+ return fmt.Errorf("%T is not a runtime.Object, cannot call SetControllerReference", owner)
}
- if len(ro.DeepCopyObject().GetObjectKind().GroupVersionKind().Group) == 0 {
- return fmt.Errorf("%T metadata have not been set, cannot call setOwnerReference", owner)
+ gvk := ro.GetObjectKind().GroupVersionKind()
+ if gvk.Kind == "" {
+ return fmt.Errorf("%T has no GVK set in its metadata, cannot call SetControllerReference", owner)
}
controlled.SetOwnerReferences([]metav1.OwnerReference{
{
- APIVersion: ro.GetObjectKind().GroupVersionKind().GroupVersion().String(),
- Kind: ro.GetObjectKind().GroupVersionKind().Kind,
+ APIVersion: gvk.GroupVersion().String(),
+ Kind: gvk.Kind,
Name: owner.GetName(),
UID: owner.GetUID(),
BlockOwnerDeletion: ptr.To(true),
diff --git a/internal/cnpgi/operator/specs/ownership_test.go b/internal/cnpgi/operator/specs/ownership_test.go
new file mode 100644
index 0000000..9be7a5d
--- /dev/null
+++ b/internal/cnpgi/operator/specs/ownership_test.go
@@ -0,0 +1,100 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package specs
+
+import (
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ rbacv1 "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+)
+
+var _ = Describe("SetControllerReference", func() {
+ It("should set the owner reference from the owner's TypeMeta", func() {
+ owner := &cnpgv1.Cluster{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "postgresql.cnpg.io/v1",
+ Kind: "Cluster",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-cluster",
+ Namespace: "default",
+ UID: types.UID("test-uid"),
+ },
+ }
+ controlled := &rbacv1.Role{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-role",
+ Namespace: "default",
+ },
+ }
+
+ Expect(SetControllerReference(owner, controlled)).To(Succeed())
+ Expect(controlled.OwnerReferences).To(HaveLen(1))
+ Expect(controlled.OwnerReferences[0].APIVersion).To(Equal("postgresql.cnpg.io/v1"))
+ Expect(controlled.OwnerReferences[0].Kind).To(Equal("Cluster"))
+ Expect(controlled.OwnerReferences[0].Name).To(Equal("my-cluster"))
+ Expect(controlled.OwnerReferences[0].UID).To(Equal(types.UID("test-uid")))
+ Expect(*controlled.OwnerReferences[0].Controller).To(BeTrue())
+ Expect(*controlled.OwnerReferences[0].BlockOwnerDeletion).To(BeTrue())
+ })
+
+ It("should work with a custom CNPG API group", func() {
+ owner := &cnpgv1.Cluster{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "mycompany.io/v1",
+ Kind: "Cluster",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-cluster",
+ UID: types.UID("test-uid"),
+ },
+ }
+ controlled := &rbacv1.Role{}
+
+ Expect(SetControllerReference(owner, controlled)).To(Succeed())
+ Expect(controlled.OwnerReferences[0].APIVersion).To(Equal("mycompany.io/v1"))
+ })
+
+ It("should fail when the owner has no GVK set", func() {
+ owner := &cnpgv1.Cluster{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-cluster",
+ },
+ }
+ controlled := &rbacv1.Role{}
+
+ err := SetControllerReference(owner, controlled)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("has no GVK set"))
+ })
+
+ It("should fail when the owner does not implement runtime.Object", func() {
+ // metav1.ObjectMeta satisfies metav1.Object but not runtime.Object.
+ owner := &metav1.ObjectMeta{Name: "my-cluster"}
+ controlled := &rbacv1.Role{}
+
+ err := SetControllerReference(owner, controlled)
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("is not a runtime.Object"))
+ })
+})
diff --git a/internal/cnpgi/operator/specs/role.go b/internal/cnpgi/operator/specs/role.go
index 0c5fa70..a53278d 100644
--- a/internal/cnpgi/operator/specs/role.go
+++ b/internal/cnpgi/operator/specs/role.go
@@ -21,6 +21,7 @@ package specs
import (
"fmt"
+ "slices"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/machinery/pkg/stringset"
@@ -35,15 +36,20 @@ func BuildRole(
cluster *cnpgv1.Cluster,
barmanObjects []barmancloudv1.ObjectStore,
) *rbacv1.Role {
- role := &rbacv1.Role{
+ return &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Namespace: cluster.Namespace,
Name: GetRBACName(cluster.Name),
+ Labels: BuildLabels(cluster),
},
-
- Rules: []rbacv1.PolicyRule{},
+ Rules: BuildRoleRules(barmanObjects),
}
+}
+// BuildRoleRules builds the RBAC PolicyRules for the given ObjectStores.
+//
+//nolint:goconst
+func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRule {
secretsSet := stringset.New()
barmanObjectsSet := stringset.New()
@@ -54,11 +60,10 @@ func BuildRole(
}
}
- role.Rules = append(
- role.Rules,
- rbacv1.PolicyRule{
+ return []rbacv1.PolicyRule{
+ {
APIGroups: []string{
- "barmancloud.cnpg.io",
+ barmancloudv1.GroupVersion.Group,
},
Verbs: []string{
"get",
@@ -70,9 +75,9 @@ func BuildRole(
},
ResourceNames: barmanObjectsSet.ToSortedList(),
},
- rbacv1.PolicyRule{
+ {
APIGroups: []string{
- "barmancloud.cnpg.io",
+ barmancloudv1.GroupVersion.Group,
},
Verbs: []string{
"update",
@@ -82,7 +87,7 @@ func BuildRole(
},
ResourceNames: barmanObjectsSet.ToSortedList(),
},
- rbacv1.PolicyRule{
+ {
APIGroups: []string{
"",
},
@@ -96,9 +101,25 @@ func BuildRole(
},
ResourceNames: secretsSet.ToSortedList(),
},
- )
+ }
+}
- return role
+// ObjectStoreNamesFromRole extracts the ObjectStore names referenced
+// by a plugin-managed Role. It finds the objectstores rule
+// semantically (by APIGroup and Resource, not by index) and returns
+// a copy of its ResourceNames. Returns nil if no matching rule is
+// found.
+func ObjectStoreNamesFromRole(role *rbacv1.Role) []string {
+ for _, rule := range role.Rules {
+ if len(rule.APIGroups) == 1 &&
+ rule.APIGroups[0] == barmancloudv1.GroupVersion.Group &&
+ len(rule.Resources) == 1 &&
+ rule.Resources[0] == "objectstores" {
+ return slices.Clone(rule.ResourceNames)
+ }
+ }
+
+ return nil
}
// BuildRoleBinding builds the role binding object for this cluster
@@ -109,6 +130,7 @@ func BuildRoleBinding(
ObjectMeta: metav1.ObjectMeta{
Namespace: cluster.Namespace,
Name: GetRBACName(cluster.Name),
+ Labels: BuildLabels(cluster),
},
Subjects: []rbacv1.Subject{
{
diff --git a/internal/cnpgi/operator/specs/role_test.go b/internal/cnpgi/operator/specs/role_test.go
new file mode 100644
index 0000000..bb5c9a1
--- /dev/null
+++ b/internal/cnpgi/operator/specs/role_test.go
@@ -0,0 +1,210 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package specs
+
+import (
+ barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ rbacv1 "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+)
+
+func newTestObjectStore(name, secretName string) barmancloudv1.ObjectStore {
+ return barmancloudv1.ObjectStore{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: "default",
+ },
+ Spec: barmancloudv1.ObjectStoreSpec{
+ Configuration: barmanapi.BarmanObjectStoreConfiguration{
+ DestinationPath: "s3://bucket/path",
+ BarmanCredentials: barmanapi.BarmanCredentials{
+ AWS: &barmanapi.S3Credentials{
+ AccessKeyIDReference: &machineryapi.SecretKeySelector{
+ LocalObjectReference: machineryapi.LocalObjectReference{
+ Name: secretName,
+ },
+ Key: "ACCESS_KEY_ID",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+var _ = Describe("BuildRoleRules", func() {
+ It("should produce 3 rules with correct ResourceNames", func() {
+ objects := []barmancloudv1.ObjectStore{
+ newTestObjectStore("store-a", "secret-a"),
+ newTestObjectStore("store-b", "secret-b"),
+ }
+ rules := BuildRoleRules(objects)
+ Expect(rules).To(HaveLen(3))
+
+ Expect(rules[0].APIGroups).To(Equal([]string{barmancloudv1.GroupVersion.Group}))
+ Expect(rules[0].Resources).To(Equal([]string{"objectstores"}))
+ Expect(rules[0].ResourceNames).To(ConsistOf("store-a", "store-b"))
+
+ Expect(rules[1].APIGroups).To(Equal([]string{barmancloudv1.GroupVersion.Group}))
+ Expect(rules[1].Resources).To(Equal([]string{"objectstores/status"}))
+ Expect(rules[1].ResourceNames).To(ConsistOf("store-a", "store-b"))
+
+ Expect(rules[2].APIGroups).To(Equal([]string{""}))
+ Expect(rules[2].Resources).To(Equal([]string{"secrets"}))
+ Expect(rules[2].ResourceNames).To(ConsistOf("secret-a", "secret-b"))
+ })
+
+ It("should produce rules with empty ResourceNames for empty input", func() {
+ rules := BuildRoleRules(nil)
+ Expect(rules).To(HaveLen(3))
+ Expect(rules[0].ResourceNames).To(BeEmpty())
+ Expect(rules[0].ResourceNames).NotTo(BeNil())
+ Expect(rules[1].ResourceNames).To(BeEmpty())
+ Expect(rules[2].ResourceNames).To(BeEmpty())
+ })
+
+ It("should deduplicate secret names across ObjectStores", func() {
+ objects := []barmancloudv1.ObjectStore{
+ newTestObjectStore("store-a", "shared-secret"),
+ newTestObjectStore("store-b", "shared-secret"),
+ }
+ rules := BuildRoleRules(objects)
+ Expect(rules[2].ResourceNames).To(Equal([]string{"shared-secret"}))
+ })
+})
+
+var _ = Describe("BuildRole", func() {
+ It("should set the cluster label", func() {
+ cluster := &cnpgv1.Cluster{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-cluster",
+ Namespace: "default",
+ },
+ }
+ role := BuildRole(cluster, nil)
+ Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "my-cluster"))
+ Expect(role.Name).To(Equal("my-cluster-barman-cloud"))
+ Expect(role.Namespace).To(Equal("default"))
+ })
+})
+
+var _ = Describe("BuildRoleRules / ObjectStoreNamesFromRole round-trip", func() {
+ It("should recover the same ObjectStore names from built rules", func() {
+ objects := []barmancloudv1.ObjectStore{
+ newTestObjectStore("store-a", "secret-a"),
+ newTestObjectStore("store-b", "secret-b"),
+ }
+ rules := BuildRoleRules(objects)
+ role := &rbacv1.Role{Rules: rules}
+ names := ObjectStoreNamesFromRole(role)
+ Expect(names).To(ConsistOf("store-a", "store-b"))
+ })
+
+ It("should recover empty names from rules built with no ObjectStores", func() {
+ rules := BuildRoleRules(nil)
+ role := &rbacv1.Role{Rules: rules}
+ names := ObjectStoreNamesFromRole(role)
+ Expect(names).To(BeEmpty())
+ })
+})
+
+var _ = Describe("ObjectStoreNamesFromRole", func() {
+ It("should extract ObjectStore names from a well-formed Role", func() {
+ role := &rbacv1.Role{
+ Rules: []rbacv1.PolicyRule{
+ {
+ APIGroups: []string{barmancloudv1.GroupVersion.Group},
+ Resources: []string{"objectstores"},
+ ResourceNames: []string{"store-a", "store-b"},
+ },
+ {
+ APIGroups: []string{""},
+ Resources: []string{"secrets"},
+ ResourceNames: []string{"secret-a"},
+ },
+ },
+ }
+ Expect(ObjectStoreNamesFromRole(role)).To(Equal([]string{"store-a", "store-b"}))
+ })
+
+ It("should return nil for a Role with no matching rule", func() {
+ role := &rbacv1.Role{
+ Rules: []rbacv1.PolicyRule{
+ {
+ APIGroups: []string{""},
+ Resources: []string{"secrets"},
+ ResourceNames: []string{"secret-a"},
+ },
+ },
+ }
+ Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
+ })
+
+ It("should return nil for a Role with empty rules", func() {
+ role := &rbacv1.Role{}
+ Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
+ })
+
+ It("should not match a rule with a different APIGroup", func() {
+ role := &rbacv1.Role{
+ Rules: []rbacv1.PolicyRule{
+ {
+ APIGroups: []string{"other.io"},
+ Resources: []string{"objectstores"},
+ ResourceNames: []string{"store-a"},
+ },
+ },
+ }
+ Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
+ })
+
+ It("should not match a rule with multiple APIGroups", func() {
+ role := &rbacv1.Role{
+ Rules: []rbacv1.PolicyRule{
+ {
+ APIGroups: []string{barmancloudv1.GroupVersion.Group, "other.io"},
+ Resources: []string{"objectstores"},
+ ResourceNames: []string{"store-a"},
+ },
+ },
+ }
+ Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
+ })
+
+ It("should not match a rule for objectstores/status", func() {
+ role := &rbacv1.Role{
+ Rules: []rbacv1.PolicyRule{
+ {
+ APIGroups: []string{barmancloudv1.GroupVersion.Group},
+ Resources: []string{"objectstores/status"},
+ ResourceNames: []string{"store-a"},
+ },
+ },
+ }
+ Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
+ })
+})
diff --git a/internal/cnpgi/restore/manager.go b/internal/cnpgi/restore/manager.go
index 575feb7..bcfe8c9 100644
--- a/internal/cnpgi/restore/manager.go
+++ b/internal/cnpgi/restore/manager.go
@@ -22,34 +22,23 @@ package restore
import (
"context"
- cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/machinery/pkg/log"
"github.com/spf13/viper"
corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime"
- utilruntime "k8s.io/apimachinery/pkg/util/runtime"
- clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/common"
)
-var scheme = runtime.NewScheme()
-
-func init() {
- utilruntime.Must(barmancloudv1.AddToScheme(scheme))
- utilruntime.Must(cnpgv1.AddToScheme(scheme))
- utilruntime.Must(clientgoscheme.AddToScheme(scheme))
-}
-
// Start starts the sidecar informers and CNPG-i server
func Start(ctx context.Context) error {
setupLog := log.FromContext(ctx)
setupLog.Info("Starting barman cloud instance plugin")
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
- Scheme: scheme,
+ Scheme: common.GenerateScheme(ctx),
Client: client.Options{
Cache: &client.CacheOptions{
DisableFor: []client.Object{
diff --git a/internal/controller/objectstore_controller.go b/internal/controller/objectstore_controller.go
index 31fe83f..e0a77dd 100644
--- a/internal/controller/objectstore_controller.go
+++ b/internal/controller/objectstore_controller.go
@@ -21,14 +21,23 @@ package controller
import (
"context"
+ "errors"
"fmt"
+ "slices"
"github.com/cloudnative-pg/machinery/pkg/log"
+ rbacv1 "k8s.io/api/rbac/v1"
+ apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
)
// ObjectStoreReconciler reconciles a ObjectStore object.
@@ -40,33 +49,93 @@ type ObjectStoreReconciler struct {
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;patch;update;get;list;watch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;patch;update;get;list;watch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=create;list;get;watch;delete
-// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/finalizers,verbs=update
// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=backups,verbs=get;list;watch
+// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/finalizers,verbs=update
// +kubebuilder:rbac:groups=barmancloud.cnpg.io,resources=objectstores,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=barmancloud.cnpg.io,resources=objectstores/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=barmancloud.cnpg.io,resources=objectstores/finalizers,verbs=update
-// Reconcile is part of the main kubernetes reconciliation loop which aims to
-// move the current state of the cluster closer to the desired state.
-// TODO(user): Modify the Reconcile function to compare the state specified by
-// the ObjectStore object against the actual cluster state, and then
-// perform operations to make the cluster state reflect the state specified by
-// the user.
-//
-// For more details, check Reconcile and its Result here:
-// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile
-func (r *ObjectStoreReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) {
- _ = log.FromContext(ctx)
+// Reconcile ensures that the RBAC Role for each Cluster referencing
+// this ObjectStore is up to date with the current ObjectStore spec.
+// It discovers affected Roles by listing plugin-managed Roles and
+// inspecting their rules, without needing access to Cluster objects.
+func (r *ObjectStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ contextLogger := log.FromContext(ctx).WithValues(
+ "objectStoreName", req.Name,
+ "namespace", req.Namespace,
+ )
+ ctx = log.IntoContext(ctx, contextLogger)
- // TODO(user): your logic here
+ contextLogger.Info("ObjectStore reconciliation start")
- return ctrl.Result{}, nil
+ // NOTE: Roles created before the introduction of ClusterLabelName
+ // are not discovered here. The Pre hook patches the label on every
+ // Cluster reconciliation, so unlabeled Roles are picked up after
+ // the next Cluster reconcile cycle.
+ var roleList rbacv1.RoleList
+ if err := r.List(ctx, &roleList,
+ client.InNamespace(req.Namespace),
+ client.HasLabels{metadata.ClusterLabelName},
+ ); err != nil {
+ return ctrl.Result{}, fmt.Errorf("while listing roles: %w", err)
+ }
+
+ var errs []error
+ for i := range roleList.Items {
+ role := &roleList.Items[i]
+
+ objectStoreNames := specs.ObjectStoreNamesFromRole(role)
+ if !slices.Contains(objectStoreNames, req.Name) {
+ continue
+ }
+
+ contextLogger.Info("Reconciling RBAC for role",
+ "roleName", role.Name)
+
+ if err := r.reconcileRoleRules(ctx, role, objectStoreNames); err != nil {
+ contextLogger.Error(err, "Failed to reconcile RBAC for role",
+ "roleName", role.Name)
+ errs = append(errs, fmt.Errorf("while reconciling role %s: %w", role.Name, err))
+ }
+ }
+
+ contextLogger.Info("ObjectStore reconciliation completed")
+ return ctrl.Result{}, errors.Join(errs...)
+}
+
+// reconcileRoleRules fetches the ObjectStores referenced by the
+// Role and patches its rules to match the current specs.
+func (r *ObjectStoreReconciler) reconcileRoleRules(
+ ctx context.Context,
+ role *rbacv1.Role,
+ objectStoreNames []string,
+) error {
+ contextLogger := log.FromContext(ctx)
+ barmanObjects := make([]barmancloudv1.ObjectStore, 0, len(objectStoreNames))
+
+ for _, name := range objectStoreNames {
+ var barmanObject barmancloudv1.ObjectStore
+ if err := r.Get(ctx, client.ObjectKey{
+ Namespace: role.Namespace,
+ Name: name,
+ }, &barmanObject); err != nil {
+ if apierrs.IsNotFound(err) {
+ contextLogger.Info("ObjectStore not found, skipping",
+ "objectStoreName", name)
+ continue
+ }
+ return fmt.Errorf("while getting ObjectStore %s: %w", name, err)
+ }
+ barmanObjects = append(barmanObjects, barmanObject)
+ }
+
+ return rbac.EnsureRoleRules(ctx, r.Client, client.ObjectKeyFromObject(role), barmanObjects)
}
// SetupWithManager sets up the controller with the Manager.
func (r *ObjectStoreReconciler) SetupWithManager(mgr ctrl.Manager) error {
err := ctrl.NewControllerManagedBy(mgr).
- For(&barmancloudv1.ObjectStore{}).
+ For(&barmancloudv1.ObjectStore{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Complete(r)
if err != nil {
return fmt.Errorf("unable to create controller: %w", err)
diff --git a/internal/controller/objectstore_controller_test.go b/internal/controller/objectstore_controller_test.go
index 6c163d3..0f64ac5 100644
--- a/internal/controller/objectstore_controller_test.go
+++ b/internal/controller/objectstore_controller_test.go
@@ -21,71 +21,382 @@ package controller
import (
"context"
+ "fmt"
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
- "k8s.io/apimachinery/pkg/api/errors"
+ machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ rbacv1 "k8s.io/api/rbac/v1"
+ apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/types"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
+ "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
-
- . "github.com/onsi/ginkgo/v2"
- . "github.com/onsi/gomega"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
)
-var _ = Describe("ObjectStore Controller", func() {
- Context("When reconciling a resource", func() {
- const resourceName = "test-resource"
+func newFakeScheme() *runtime.Scheme {
+ s := runtime.NewScheme()
+ utilruntime.Must(rbacv1.AddToScheme(s))
+ barmancloudv1.AddKnownTypes(s)
+ return s
+}
- ctx := context.Background()
-
- typeNamespacedName := types.NamespacedName{
- Name: resourceName,
- Namespace: "default", // TODO(user):Modify as needed
- }
- objectstore := &barmancloudv1.ObjectStore{}
-
- BeforeEach(func() {
- By("creating the custom resource for the Kind ObjectStore")
- err := k8sClient.Get(ctx, typeNamespacedName, objectstore)
- if err != nil && errors.IsNotFound(err) {
- resource := &barmancloudv1.ObjectStore{
- ObjectMeta: metav1.ObjectMeta{
- Name: resourceName,
- Namespace: "default",
+func newTestObjectStore(name, namespace, secretName string) *barmancloudv1.ObjectStore {
+ return &barmancloudv1.ObjectStore{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: name,
+ Namespace: namespace,
+ },
+ Spec: barmancloudv1.ObjectStoreSpec{
+ Configuration: barmanapi.BarmanObjectStoreConfiguration{
+ DestinationPath: "s3://bucket/path",
+ BarmanCredentials: barmanapi.BarmanCredentials{
+ AWS: &barmanapi.S3Credentials{
+ AccessKeyIDReference: &machineryapi.SecretKeySelector{
+ LocalObjectReference: machineryapi.LocalObjectReference{
+ Name: secretName,
+ },
+ Key: "ACCESS_KEY_ID",
+ },
},
- Spec: barmancloudv1.ObjectStoreSpec{
- Configuration: barmanapi.BarmanObjectStoreConfiguration{DestinationPath: "/tmp"},
- },
- // TODO(user): Specify other spec details if needed.
- }
- Expect(k8sClient.Create(ctx, resource)).To(Succeed())
- }
- })
+ },
+ },
+ },
+ }
+}
- AfterEach(func() {
- // TODO(user): Cleanup logic after each test, like removing the resource instance.
- resource := &barmancloudv1.ObjectStore{}
- err := k8sClient.Get(ctx, typeNamespacedName, resource)
- Expect(err).NotTo(HaveOccurred())
+func newLabeledRole(clusterName, namespace string, objectStores []barmancloudv1.ObjectStore) *rbacv1.Role {
+ return &rbacv1.Role{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: specs.GetRBACName(clusterName),
+ Namespace: namespace,
+ Labels: map[string]string{
+ metadata.ClusterLabelName: clusterName,
+ },
+ },
+ Rules: specs.BuildRoleRules(objectStores),
+ }
+}
- By("Cleanup the specific resource instance ObjectStore")
- Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
- })
- It("should successfully reconcile the resource", func() {
- By("Reconciling the created resource")
- controllerReconciler := &ObjectStoreReconciler{
- Client: k8sClient,
- Scheme: k8sClient.Scheme(),
+var _ = Describe("ObjectStoreReconciler", func() {
+ var (
+ ctx context.Context
+ scheme *runtime.Scheme
+ )
+
+ BeforeEach(func() {
+ ctx = context.Background()
+ scheme = newFakeScheme()
+ })
+
+ Describe("Reconcile", func() {
+ It("should update Role rules when ObjectStore credentials change", func() {
+ oldStore := newTestObjectStore("my-store", "default", "old-secret")
+ role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*oldStore})
+
+ // Update the ObjectStore with new credentials
+ newStore := newTestObjectStore("my-store", "default", "new-secret")
+
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(role, newStore).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
}
- _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
- NamespacedName: typeNamespacedName,
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "my-store",
+ Namespace: "default",
+ },
})
Expect(err).NotTo(HaveOccurred())
- // TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
- // Example: If you expect a certain status condition after reconciliation, verify it here.
+ Expect(result).To(Equal(reconcile.Result{}))
+
+ var updatedRole rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "my-cluster-barman-cloud",
+ }, &updatedRole)).To(Succeed())
+
+ secretsRule := updatedRole.Rules[2]
+ Expect(secretsRule.ResourceNames).To(ContainElement("new-secret"))
+ Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
+ })
+
+ It("should skip Roles that don't reference the ObjectStore", func() {
+ otherStore := newTestObjectStore("other-store", "default", "other-creds")
+ role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*otherStore})
+
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(role).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
+ }
+
+ var before rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "my-cluster-barman-cloud",
+ }, &before)).To(Succeed())
+
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "unrelated-store",
+ Namespace: "default",
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{}))
+
+ var after rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "my-cluster-barman-cloud",
+ }, &after)).To(Succeed())
+
+ Expect(after.ResourceVersion).To(Equal(before.ResourceVersion))
+ })
+
+ It("should succeed with no labeled Roles in the namespace", func() {
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
+ }
+
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "my-store",
+ Namespace: "default",
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{}))
+ })
+
+ It("should handle deleted ObjectStores gracefully", func() {
+ storeA := newTestObjectStore("store-a", "default", "secret-a")
+ storeB := newTestObjectStore("store-b", "default", "secret-b")
+ role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*storeA, *storeB})
+
+ // Only store-a exists; store-b was deleted
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(role, storeA).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
+ }
+
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "store-b",
+ Namespace: "default",
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{}))
+
+ var updatedRole rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "my-cluster-barman-cloud",
+ }, &updatedRole)).To(Succeed())
+
+ objectStoreRule := updatedRole.Rules[0]
+ Expect(objectStoreRule.ResourceNames).To(ContainElement("store-a"))
+ Expect(objectStoreRule.ResourceNames).NotTo(ContainElement("store-b"))
+ })
+
+ It("should not panic on a Role with empty rules", func() {
+ emptyRole := &rbacv1.Role{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "empty-barman-cloud",
+ Namespace: "default",
+ Labels: map[string]string{
+ metadata.ClusterLabelName: "empty",
+ },
+ },
+ }
+
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(emptyRole).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
+ }
+
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "my-store",
+ Namespace: "default",
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{}))
+ })
+
+ It("should produce empty ResourceNames when all ObjectStores are deleted", func() {
+ store := newTestObjectStore("my-store", "default", "aws-creds")
+ role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*store})
+
+ // Don't add the ObjectStore to the fake client (simulates deletion)
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(role).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
+ }
+
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "my-store",
+ Namespace: "default",
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{}))
+
+ var updatedRole rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: "my-cluster-barman-cloud",
+ }, &updatedRole)).To(Succeed())
+
+ // All rules should have empty ResourceNames
+ Expect(updatedRole.Rules[0].ResourceNames).To(BeEmpty())
+ Expect(updatedRole.Rules[1].ResourceNames).To(BeEmpty())
+ Expect(updatedRole.Rules[2].ResourceNames).To(BeEmpty())
+ })
+
+ It("should return an error when listing Roles fails", func() {
+ internalErr := apierrs.NewInternalError(fmt.Errorf("etcd timeout"))
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithInterceptorFuncs(interceptor.Funcs{
+ List: func(ctx context.Context, c client.WithWatch, list client.ObjectList, opts ...client.ListOption) error {
+ if _, ok := list.(*rbacv1.RoleList); ok {
+ return internalErr
+ }
+ return c.List(ctx, list, opts...)
+ },
+ }).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{Client: fakeClient, Scheme: scheme}
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{Name: "my-store", Namespace: "default"},
+ })
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("while listing roles"))
+ })
+
+ It("should return an error when fetching an ObjectStore fails with a transient error", func() {
+ store := newTestObjectStore("my-store", "default", "aws-creds")
+ role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*store})
+
+ internalErr := apierrs.NewInternalError(fmt.Errorf("etcd timeout"))
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(role).
+ WithInterceptorFuncs(interceptor.Funcs{
+ Get: func(ctx context.Context, c client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+ if _, ok := obj.(*barmancloudv1.ObjectStore); ok {
+ return internalErr
+ }
+ return c.Get(ctx, key, obj, opts...)
+ },
+ }).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{Client: fakeClient, Scheme: scheme}
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{Name: "my-store", Namespace: "default"},
+ })
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("while reconciling role"))
+ })
+
+ It("should reconcile multiple Roles referencing the same ObjectStore", func() {
+ store := newTestObjectStore("shared-store", "default", "new-secret")
+ oldStore := barmancloudv1.ObjectStore{
+ ObjectMeta: metav1.ObjectMeta{Name: "shared-store", Namespace: "default"},
+ Spec: barmancloudv1.ObjectStoreSpec{
+ Configuration: barmanapi.BarmanObjectStoreConfiguration{
+ DestinationPath: "s3://bucket/path",
+ BarmanCredentials: barmanapi.BarmanCredentials{
+ AWS: &barmanapi.S3Credentials{
+ AccessKeyIDReference: &machineryapi.SecretKeySelector{
+ LocalObjectReference: machineryapi.LocalObjectReference{Name: "old-secret"},
+ Key: "ACCESS_KEY_ID",
+ },
+ },
+ },
+ },
+ },
+ }
+
+ role1 := newLabeledRole("cluster-1", "default", []barmancloudv1.ObjectStore{oldStore})
+ role2 := newLabeledRole("cluster-2", "default", []barmancloudv1.ObjectStore{oldStore})
+
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(role1, role2, store).
+ Build()
+
+ reconciler := &ObjectStoreReconciler{
+ Client: fakeClient,
+ Scheme: scheme,
+ }
+
+ result, err := reconciler.Reconcile(ctx, reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Name: "shared-store",
+ Namespace: "default",
+ },
+ })
+ Expect(err).NotTo(HaveOccurred())
+ Expect(result).To(Equal(reconcile.Result{}))
+
+ for _, clusterName := range []string{"cluster-1", "cluster-2"} {
+ var updatedRole rbacv1.Role
+ Expect(fakeClient.Get(ctx, client.ObjectKey{
+ Namespace: "default",
+ Name: specs.GetRBACName(clusterName),
+ }, &updatedRole)).To(Succeed())
+
+ secretsRule := updatedRole.Rules[2]
+ Expect(secretsRule.ResourceNames).To(ContainElement("new-secret"))
+ Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
+ }
})
})
})
diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go
index 18a4029..711c56a 100644
--- a/internal/controller/suite_test.go
+++ b/internal/controller/suite_test.go
@@ -20,81 +20,14 @@ SPDX-License-Identifier: Apache-2.0
package controller
import (
- "context"
- "fmt"
- "path/filepath"
- "runtime"
"testing"
- // +kubebuilder:scaffold:imports
- "k8s.io/client-go/kubernetes/scheme"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/envtest"
- logf "sigs.k8s.io/controller-runtime/pkg/log"
- "sigs.k8s.io/controller-runtime/pkg/log/zap"
-
- barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
-
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
-// These tests use Ginkgo (BDD-style Go testing framework). Refer to
-// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
-
-var (
- cfg *rest.Config
- k8sClient client.Client
- testEnv *envtest.Environment
- ctx context.Context
- cancel context.CancelFunc
-)
-
func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}
-
-var _ = BeforeSuite(func() {
- logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
-
- ctx, cancel = context.WithCancel(context.TODO())
-
- By("bootstrapping test environment")
- testEnv = &envtest.Environment{
- CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
- ErrorIfCRDPathMissing: true,
-
- // The BinaryAssetsDirectory is only required if you want to run the tests directly
- // without call the makefile target test. If not informed it will look for the
- // default path defined in controller-runtime which is /usr/local/kubebuilder/.
- // Note that you must have the required binaries setup under the bin directory to perform
- // the tests directly. When we run make test it will be setup and used automatically.
- BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
- fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
- }
-
- var err error
- // cfg is defined in this file globally.
- cfg, err = testEnv.Start()
- Expect(err).NotTo(HaveOccurred())
- Expect(cfg).NotTo(BeNil())
-
- err = barmancloudv1.AddToScheme(scheme.Scheme)
- Expect(err).NotTo(HaveOccurred())
-
- // +kubebuilder:scaffold:scheme
-
- k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
- Expect(err).NotTo(HaveOccurred())
- Expect(k8sClient).NotTo(BeNil())
-})
-
-var _ = AfterSuite(func() {
- By("tearing down the test environment")
- cancel()
- err := testEnv.Stop()
- Expect(err).NotTo(HaveOccurred())
-})
diff --git a/internal/scheme/cnpg.go b/internal/scheme/cnpg.go
new file mode 100644
index 0000000..43146c3
--- /dev/null
+++ b/internal/scheme/cnpg.go
@@ -0,0 +1,54 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package scheme
+
+import (
+ "context"
+
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ "github.com/cloudnative-pg/machinery/pkg/log"
+ "github.com/spf13/viper"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// AddCNPGToScheme registers CNPG types into the given scheme using
+// the API group configured via CUSTOM_CNPG_GROUP/CUSTOM_CNPG_VERSION
+// environment variables, defaulting to postgresql.cnpg.io/v1.
+// This allows the plugin to work with any CNPG-based operator.
+func AddCNPGToScheme(ctx context.Context, s *runtime.Scheme) {
+ cnpgGroup := viper.GetString("custom-cnpg-group")
+ cnpgVersion := viper.GetString("custom-cnpg-version")
+ if len(cnpgGroup) == 0 {
+ cnpgGroup = cnpgv1.SchemeGroupVersion.Group
+ }
+ if len(cnpgVersion) == 0 {
+ cnpgVersion = cnpgv1.SchemeGroupVersion.Version
+ }
+
+ schemeGroupVersion := schema.GroupVersion{Group: cnpgGroup, Version: cnpgVersion}
+ s.AddKnownTypes(schemeGroupVersion,
+ &cnpgv1.Cluster{}, &cnpgv1.ClusterList{},
+ &cnpgv1.Backup{}, &cnpgv1.BackupList{},
+ &cnpgv1.ScheduledBackup{}, &cnpgv1.ScheduledBackupList{},
+ )
+
+ log.FromContext(ctx).Info("CNPG types registration", "schemeGroupVersion", schemeGroupVersion)
+}
diff --git a/internal/scheme/cnpg_test.go b/internal/scheme/cnpg_test.go
new file mode 100644
index 0000000..67d2151
--- /dev/null
+++ b/internal/scheme/cnpg_test.go
@@ -0,0 +1,116 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package scheme
+
+import (
+ "context"
+
+ cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/spf13/viper"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+var _ = Describe("AddCNPGToScheme", func() {
+ var s *runtime.Scheme
+
+ BeforeEach(func() {
+ s = runtime.NewScheme()
+ })
+
+ AfterEach(func() {
+ viper.Reset()
+ })
+
+ It("should register CNPG types under the default group and version", func() {
+ AddCNPGToScheme(context.Background(), s)
+
+ gvks, _, err := s.ObjectKinds(&cnpgv1.Cluster{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(gvks).To(ContainElement(schema.GroupVersionKind{
+ Group: cnpgv1.SchemeGroupVersion.Group,
+ Version: cnpgv1.SchemeGroupVersion.Version,
+ Kind: "Cluster",
+ }))
+ })
+
+ It("should register Backup and ScheduledBackup under the default group", func() {
+ AddCNPGToScheme(context.Background(), s)
+
+ gvks, _, err := s.ObjectKinds(&cnpgv1.Backup{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(gvks).To(ContainElement(HaveField("Group", cnpgv1.SchemeGroupVersion.Group)))
+
+ gvks, _, err = s.ObjectKinds(&cnpgv1.ScheduledBackup{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(gvks).To(ContainElement(HaveField("Group", cnpgv1.SchemeGroupVersion.Group)))
+ })
+
+ It("should register CNPG types under a custom group", func() {
+ viper.Set("custom-cnpg-group", "mycompany.io")
+
+ AddCNPGToScheme(context.Background(), s)
+
+ gvks, _, err := s.ObjectKinds(&cnpgv1.Cluster{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(gvks).To(ContainElement(schema.GroupVersionKind{
+ Group: "mycompany.io",
+ Version: cnpgv1.SchemeGroupVersion.Version,
+ Kind: "Cluster",
+ }))
+ // The default group must not be registered
+ Expect(s.Recognizes(schema.GroupVersionKind{
+ Group: cnpgv1.SchemeGroupVersion.Group,
+ Version: cnpgv1.SchemeGroupVersion.Version,
+ Kind: "Cluster",
+ })).To(BeFalse())
+ })
+
+ It("should register CNPG types under a custom version", func() {
+ viper.Set("custom-cnpg-version", "v2")
+
+ AddCNPGToScheme(context.Background(), s)
+
+ gvks, _, err := s.ObjectKinds(&cnpgv1.Cluster{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(gvks).To(ContainElement(schema.GroupVersionKind{
+ Group: cnpgv1.SchemeGroupVersion.Group,
+ Version: "v2",
+ Kind: "Cluster",
+ }))
+ })
+
+ It("should register CNPG types under both a custom group and custom version", func() {
+ viper.Set("custom-cnpg-group", "mycompany.io")
+ viper.Set("custom-cnpg-version", "v2")
+
+ AddCNPGToScheme(context.Background(), s)
+
+ gvks, _, err := s.ObjectKinds(&cnpgv1.Cluster{})
+ Expect(err).NotTo(HaveOccurred())
+ Expect(gvks).To(ContainElement(schema.GroupVersionKind{
+ Group: "mycompany.io",
+ Version: "v2",
+ Kind: "Cluster",
+ }))
+ })
+})
diff --git a/internal/scheme/doc.go b/internal/scheme/doc.go
new file mode 100644
index 0000000..7128523
--- /dev/null
+++ b/internal/scheme/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+// Package scheme provides utilities for building runtime schemes
+// with support for custom CNPG API groups.
+package scheme
diff --git a/internal/scheme/suite_test.go b/internal/scheme/suite_test.go
new file mode 100644
index 0000000..289f44c
--- /dev/null
+++ b/internal/scheme/suite_test.go
@@ -0,0 +1,32 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package scheme
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestScheme(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Scheme Suite")
+}
diff --git a/kubernetes/kustomization.yaml b/kubernetes/kustomization.yaml
index b4ebc9e..eda8b8c 100644
--- a/kubernetes/kustomization.yaml
+++ b/kubernetes/kustomization.yaml
@@ -9,6 +9,7 @@ resources:
- service.yaml
- ../config/crd
- ../config/rbac
+# If you change newName, update the e2e overlay in test/e2e/e2e_suite_test.go too.
images:
- name: plugin-barman-cloud
newName: ghcr.io/cloudnative-pg/plugin-barman-cloud-testing
diff --git a/manifest.yaml b/manifest.yaml
index 60b755e..3b99c39 100644
--- a/manifest.yaml
+++ b/manifest.yaml
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
- controller-gen.kubebuilder.io/version: v0.20.1
+ controller-gen.kubebuilder.io/version: v0.21.0
name: objectstores.barmancloud.cnpg.io
spec:
group: barmancloud.cnpg.io
@@ -143,10 +143,11 @@ spec:
description: |-
Compress a backup file (a tar file per tablespace) while streaming it
to the object store. Available options are empty string (no
- compression, default), `gzip`, `bzip2`, and `snappy`.
+ compression, default), `gzip`, `bzip2`, `lz4`, and `snappy`.
enum:
- bzip2
- gzip
+ - lz4
- snappy
type: string
encryption:
diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go
index 4d62e02..bbf7b90 100644
--- a/test/e2e/e2e_suite_test.go
+++ b/test/e2e/e2e_suite_test.go
@@ -37,6 +37,7 @@ import (
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/kustomize"
_ "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/tests/backup"
+ _ "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/tests/credentialrotation"
_ "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/tests/replicacluster"
. "github.com/onsi/ginkgo/v2"
@@ -57,9 +58,11 @@ var _ = SynchronizedBeforeSuite(func(ctx SpecContext) []byte {
const barmanCloudKustomizationPath = "./kustomize/kubernetes/"
barmanCloudKustomization := &kustomizeTypes.Kustomization{
Resources: []string{barmanCloudKustomizationPath},
+ // Override the image from the base kustomization (kubernetes/kustomization.yaml)
+ // with the locally-built one. The Name must match the newName in the base.
Images: []kustomizeTypes.Image{
{
- Name: "docker.io/library/plugin-barman-cloud",
+ Name: "ghcr.io/cloudnative-pg/plugin-barman-cloud-testing",
NewName: "registry.barman-cloud-plugin:5000/plugin-barman-cloud",
NewTag: "testing",
},
diff --git a/test/e2e/internal/client/client.go b/test/e2e/internal/client/client.go
index d3fe21e..ec85f5c 100644
--- a/test/e2e/internal/client/client.go
+++ b/test/e2e/internal/client/client.go
@@ -91,12 +91,11 @@ func addScheme(cl client.Client) error {
if err := certmanagerv1.AddToScheme(scheme); err != nil {
return fmt.Errorf("failed to add cert-manager/v1 to scheme: %w", err)
}
- if err := pluginBarmanCloudV1.AddToScheme(scheme); err != nil {
- return fmt.Errorf("failed to add plugin-barman-cloud/v1 to scheme: %w", err)
- }
if err := cloudnativepgv1.AddToScheme(scheme); err != nil {
return fmt.Errorf("failed to add cloudnativepg/v1 to scheme: %w", err)
}
+
+ pluginBarmanCloudV1.AddKnownTypes(scheme)
return nil
}
diff --git a/test/e2e/internal/tests/credentialrotation/credential_rotation.go b/test/e2e/internal/tests/credentialrotation/credential_rotation.go
new file mode 100644
index 0000000..f530259
--- /dev/null
+++ b/test/e2e/internal/tests/credentialrotation/credential_rotation.go
@@ -0,0 +1,171 @@
+/*
+Copyright © contributors to CloudNativePG, established as
+CloudNativePG a Series of LF Projects, LLC.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package credentialrotation
+
+import (
+ "time"
+
+ cloudnativepgv1 "github.com/cloudnative-pg/api/pkg/api/v1"
+ corev1 "k8s.io/api/core/v1"
+ rbacv1 "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/utils/ptr"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
+ "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
+ internalClient "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/client"
+ internalCluster "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/cluster"
+ nmsp "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/namespace"
+ "github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/objectstore"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+const (
+ clusterName = "source"
+ objectStoreName = "source"
+ oldSecretName = "minio"
+ newSecretName = "minio-rotated"
+)
+
+var _ = Describe("Credential rotation", func() {
+ var namespace *corev1.Namespace
+ var cl client.Client
+
+ BeforeEach(func(ctx SpecContext) {
+ var err error
+ cl, _, err = internalClient.NewClient()
+ Expect(err).NotTo(HaveOccurred())
+ namespace, err = nmsp.CreateUniqueNamespace(ctx, cl, "cred-rotation")
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ AfterEach(func(ctx SpecContext) {
+ Expect(cl.Delete(ctx, namespace)).To(Succeed())
+ })
+
+ It("should update the Role when the ObjectStore secret reference changes", func(ctx SpecContext) {
+ By("starting the ObjectStore deployment")
+ resources := objectstore.NewMinioObjectStoreResources(namespace.Name, oldSecretName)
+ Expect(resources.Create(ctx, cl)).To(Succeed())
+
+ By("creating the ObjectStore")
+ store := objectstore.NewMinioObjectStore(namespace.Name, objectStoreName, oldSecretName)
+ Expect(cl.Create(ctx, store)).To(Succeed())
+
+ By("creating the Cluster")
+ cluster := newCluster(namespace.Name)
+ Expect(cl.Create(ctx, cluster)).To(Succeed())
+
+ By("waiting for the Cluster to be ready")
+ Eventually(func(g Gomega) {
+ g.Expect(cl.Get(ctx, types.NamespacedName{
+ Name: cluster.Name,
+ Namespace: cluster.Namespace,
+ }, cluster)).To(Succeed())
+ g.Expect(internalCluster.IsReady(*cluster)).To(BeTrue())
+ }).WithTimeout(10 * time.Minute).WithPolling(10 * time.Second).Should(Succeed())
+
+ roleKey := types.NamespacedName{
+ Name: specs.GetRBACName(clusterName),
+ Namespace: namespace.Name,
+ }
+
+ By("verifying the Role has the cluster label and references the original secret")
+ var role rbacv1.Role
+ Expect(cl.Get(ctx, roleKey, &role)).To(Succeed())
+ Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, clusterName))
+ Expect(secretNamesFromRole(&role)).To(ContainElement(oldSecretName))
+
+ By("creating a new secret with the same credentials")
+ newSecret := &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: newSecretName,
+ Namespace: namespace.Name,
+ },
+ Data: map[string][]byte{
+ "ACCESS_KEY_ID": []byte("minio"),
+ "ACCESS_SECRET_KEY": []byte("minio123"),
+ },
+ }
+ Expect(cl.Create(ctx, newSecret)).To(Succeed())
+
+ By("updating the ObjectStore to reference the new secret")
+ Expect(cl.Get(ctx, types.NamespacedName{
+ Name: objectStoreName,
+ Namespace: namespace.Name,
+ }, store)).To(Succeed())
+ store.Spec.Configuration.BarmanCredentials.AWS.AccessKeyIDReference.Name = newSecretName
+ store.Spec.Configuration.BarmanCredentials.AWS.SecretAccessKeyReference.Name = newSecretName
+ Expect(cl.Update(ctx, store)).To(Succeed())
+
+ By("waiting for the Role to reference the new secret")
+ Eventually(func(g Gomega) {
+ g.Expect(cl.Get(ctx, roleKey, &role)).To(Succeed())
+ g.Expect(secretNamesFromRole(&role)).To(ContainElement(newSecretName))
+ g.Expect(secretNamesFromRole(&role)).NotTo(ContainElement(oldSecretName))
+ }).WithTimeout(3 * time.Minute).WithPolling(5 * time.Second).Should(Succeed())
+ })
+})
+
+func newCluster(namespace string) *cloudnativepgv1.Cluster {
+ return &cloudnativepgv1.Cluster{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Cluster",
+ APIVersion: "postgresql.cnpg.io/v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: clusterName,
+ Namespace: namespace,
+ },
+ Spec: cloudnativepgv1.ClusterSpec{
+ Instances: 1,
+ ImagePullPolicy: corev1.PullAlways,
+ Plugins: []cloudnativepgv1.PluginConfiguration{
+ {
+ Name: "barman-cloud.cloudnative-pg.io",
+ Parameters: map[string]string{
+ "barmanObjectName": objectStoreName,
+ },
+ IsWALArchiver: ptr.To(true),
+ },
+ },
+ StorageConfiguration: cloudnativepgv1.StorageConfiguration{
+ Size: "1Gi",
+ },
+ },
+ }
+}
+
+func secretNamesFromRole(role *rbacv1.Role) []string {
+ for _, rule := range role.Rules {
+ if len(rule.APIGroups) == 1 &&
+ rule.APIGroups[0] == "" &&
+ len(rule.Resources) == 1 &&
+ rule.Resources[0] == "secrets" {
+ return rule.ResourceNames
+ }
+ }
+
+ return nil
+}
diff --git a/web/docs/compression.md b/web/docs/compression.md
index 2abbede..cfc6355 100644
--- a/web/docs/compression.md
+++ b/web/docs/compression.md
@@ -15,7 +15,7 @@ for space, speed, or a balance of both.
- `bzip2`
- `gzip`
-- `lz4` (WAL only)
+- `lz4`
- `snappy`
- `xz` (WAL only)
- `zstd` (WAL only)
@@ -41,3 +41,5 @@ network throughput.
| bzip2 | 25,404 | 13,886 | 395 | 67 | 5.9:1 |
| gzip | 116,281 | 3,077 | 395 | 91 | 4.3:1 |
| snappy | 8,134 | 8,341 | 395 | 166 | 2.4:1 |
+
+Numbers come from a 2021 Barman proof of concept ([EnterpriseDB/barman#344](https://github.com/EnterpriseDB/barman/issues/344#issuecomment-992547396)), which predates `lz4` support for base backups. `lz4` is not yet benchmarked.
diff --git a/web/docs/usage.md b/web/docs/usage.md
index 85bb374..a8f180a 100644
--- a/web/docs/usage.md
+++ b/web/docs/usage.md
@@ -46,7 +46,7 @@ spec:
The `.spec.configuration` schema follows the same format as the
[in-tree barman-cloud support](https://pkg.go.dev/github.com/cloudnative-pg/barman-cloud/pkg/api#BarmanObjectStoreConfiguration).
-Refer to [the CloudNativePG documentation](https://cloudnative-pg.io/documentation/preview/backup_barmanobjectstore/)
+Refer to [the CloudNativePG documentation](https://cloudnative-pg.io/documentation/current/appendixes/backup_barmanobjectstore/)
for additional details.
:::important
diff --git a/web/package.json b/web/package.json
index e8a0a4d..0844a88 100644
--- a/web/package.json
+++ b/web/package.json
@@ -15,8 +15,8 @@
"typecheck": "tsc"
},
"dependencies": {
- "@docusaurus/core": "3.9.2",
- "@docusaurus/preset-classic": "3.9.2",
+ "@docusaurus/core": "3.10.1",
+ "@docusaurus/preset-classic": "3.10.1",
"@easyops-cn/docusaurus-search-local": "^0.55.0",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
@@ -25,10 +25,10 @@
"react-dom": "^19.0.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "3.9.2",
- "@docusaurus/tsconfig": "3.9.2",
- "@docusaurus/types": "3.9.2",
- "typescript": "~5.9.0"
+ "@docusaurus/module-type-aliases": "3.10.1",
+ "@docusaurus/tsconfig": "3.10.1",
+ "@docusaurus/types": "3.10.1",
+ "typescript": "~6.0.0"
},
"browserslist": {
"production": [
@@ -43,6 +43,10 @@
]
},
"engines": {
- "node": ">=18.0"
+ "node": ">=20.0.0"
+ },
+ "resolutions": {
+ "webpackbar": "^7.0.0",
+ "serialize-javascript": ">=7.0.5"
}
}
diff --git a/web/versioned_docs/version-0.10.0/usage.md b/web/versioned_docs/version-0.10.0/usage.md
index bce6ae3..6406d38 100644
--- a/web/versioned_docs/version-0.10.0/usage.md
+++ b/web/versioned_docs/version-0.10.0/usage.md
@@ -46,7 +46,7 @@ spec:
The `.spec.configuration` schema follows the same format as the
[in-tree barman-cloud support](https://pkg.go.dev/github.com/cloudnative-pg/barman-cloud/pkg/api#BarmanObjectStoreConfiguration).
-Refer to [the CloudNativePG documentation](https://cloudnative-pg.io/documentation/preview/backup_barmanobjectstore/)
+Refer to [the CloudNativePG documentation](https://cloudnative-pg.io/documentation/current/appendixes/backup_barmanobjectstore/)
for additional details.
:::important
diff --git a/web/versioned_docs/version-0.11.0/usage.md b/web/versioned_docs/version-0.11.0/usage.md
index bce6ae3..6406d38 100644
--- a/web/versioned_docs/version-0.11.0/usage.md
+++ b/web/versioned_docs/version-0.11.0/usage.md
@@ -46,7 +46,7 @@ spec:
The `.spec.configuration` schema follows the same format as the
[in-tree barman-cloud support](https://pkg.go.dev/github.com/cloudnative-pg/barman-cloud/pkg/api#BarmanObjectStoreConfiguration).
-Refer to [the CloudNativePG documentation](https://cloudnative-pg.io/documentation/preview/backup_barmanobjectstore/)
+Refer to [the CloudNativePG documentation](https://cloudnative-pg.io/documentation/current/appendixes/backup_barmanobjectstore/)
for additional details.
:::important
diff --git a/web/versioned_docs/version-0.12.0/compression.md b/web/versioned_docs/version-0.12.0/compression.md
new file mode 100644
index 0000000..2abbede
--- /dev/null
+++ b/web/versioned_docs/version-0.12.0/compression.md
@@ -0,0 +1,43 @@
+---
+sidebar_position: 80
+---
+
+# Compression
+
+
+
+By default, backups and WAL files are archived **uncompressed**. However, the
+Barman Cloud Plugin supports multiple compression algorithms via
+`barman-cloud-backup` and `barman-cloud-wal-archive`, allowing you to optimize
+for space, speed, or a balance of both.
+
+### Supported Compression Algorithms
+
+- `bzip2`
+- `gzip`
+- `lz4` (WAL only)
+- `snappy`
+- `xz` (WAL only)
+- `zstd` (WAL only)
+
+Compression settings for base backups and WAL archives are configured
+independently. For implementation details, refer to the corresponding API
+definitions:
+
+- [`DataBackupConfiguration`](https://pkg.go.dev/github.com/cloudnative-pg/barman-cloud/pkg/api#DataBackupConfiguration)
+- [`WALBackupConfiguration`](https://pkg.go.dev/github.com/cloudnative-pg/barman-cloud/pkg/api#WalBackupConfiguration)
+
+:::important
+Compression impacts both performance and storage efficiency. Choose the right
+algorithm based on your recovery time objectives (RTO), storage capacity, and
+network throughput.
+:::
+
+## Compression Benchmark (on MinIO)
+
+| Compression | Backup Time (ms) | Restore Time (ms) | Uncompressed Size (MB) | Compressed Size (MB) | Ratio |
+| ----------- | ---------------- | ----------------- | ---------------------- | -------------------- | ----- |
+| None | 10,927 | 7,553 | 395 | 395 | 1.0:1 |
+| bzip2 | 25,404 | 13,886 | 395 | 67 | 5.9:1 |
+| gzip | 116,281 | 3,077 | 395 | 91 | 4.3:1 |
+| snappy | 8,134 | 8,341 | 395 | 166 | 2.4:1 |
diff --git a/web/versioned_docs/version-0.12.0/concepts.md b/web/versioned_docs/version-0.12.0/concepts.md
new file mode 100644
index 0000000..3832df3
--- /dev/null
+++ b/web/versioned_docs/version-0.12.0/concepts.md
@@ -0,0 +1,177 @@
+---
+sidebar_position: 10
+---
+
+# Main Concepts
+
+
+
+:::important
+Before proceeding, make sure to review the following sections of the
+CloudNativePG documentation:
+
+- [**Backup**](https://cloudnative-pg.io/documentation/current/backup/)
+- [**WAL Archiving**](https://cloudnative-pg.io/documentation/current/wal_archiving/)
+- [**Recovery**](https://cloudnative-pg.io/documentation/current/recovery/)
+:::
+
+The **Barman Cloud Plugin** enables **hot (online) backups** of PostgreSQL
+clusters in CloudNativePG through [`barman-cloud`](https://pgbarman.org),
+supporting continuous physical backups and WAL archiving to an **object
+store**—without interrupting write operations.
+
+It also supports both **full recovery** and **Point-in-Time Recovery (PITR)**
+of a PostgreSQL cluster.
+
+## The Object Store
+
+At the core is the [`ObjectStore` custom resource (CRD)](plugin-barman-cloud.v1.md#objectstorespec),
+which acts as the interface between the PostgreSQL cluster and the target
+object storage system. It allows you to configure:
+
+- **Authentication and bucket location** via the `.spec.configuration` section
+- **WAL archiving** settings—such as compression type, parallelism, and
+ server-side encryption—under `.spec.configuration.wal`
+- **Base backup options**—with similar settings for compression, concurrency,
+ and encryption—under `.spec.configuration.data`
+- **Retention policies** to manage the life-cycle of archived WALs and backups
+ via `.spec.configuration.retentionPolicy`
+
+WAL files are archived in the `wals` directory, while base backups are stored
+as **tarballs** in the `base` directory, following the
+[Barman Cloud convention](https://docs.pgbarman.org/cloud/latest/usage/#object-store-layout).
+
+The plugin also offers advanced capabilities, including
+[backup tagging](misc.md#backup-object-tagging) and
+[extra options for backups and WAL archiving](misc.md#extra-options-for-backup-and-wal-archiving).
+
+:::tip
+For details, refer to the
+[API reference for the `ObjectStore` resource](plugin-barman-cloud.v1.md#objectstorespec).
+:::
+
+## Integration with a CloudNativePG Cluster
+
+CloudNativePG can delegate continuous backup and recovery responsibilities to
+the **Barman Cloud Plugin** by configuring the `.spec.plugins` section of a
+`Cluster` resource. This setup requires a corresponding `ObjectStore` resource
+to be defined.
+
+:::important
+While it is technically possible to reuse the same `ObjectStore` for multiple
+`Cluster` resources within the same namespace, it is strongly recommended to
+dedicate one object store per PostgreSQL cluster to ensure data isolation and
+operational clarity.
+:::
+
+The following example demonstrates how to configure a CloudNativePG cluster
+named `cluster-example` to use a previously defined `ObjectStore` (also named
+`cluster-example`) in the same namespace. Setting `isWALArchiver: true` enables
+WAL archiving through the plugin:
+
+```yaml
+apiVersion: postgresql.cnpg.io/v1
+kind: Cluster
+metadata:
+ name: cluster-example
+spec:
+ # Other cluster settings...
+ plugins:
+ - name: barman-cloud.cloudnative-pg.io
+ isWALArchiver: true
+ parameters:
+ barmanObjectName: cluster-example
+```
+
+## Backup of a Postgres Cluster
+
+Once the object store is defined and the `Cluster` is configured to use the
+Barman Cloud Plugin, **WAL archiving is activated immediately** on the
+PostgreSQL primary.
+
+Physical base backups are seamlessly managed by CloudNativePG using the
+`Backup` and `ScheduledBackup` resources, respectively for
+[on-demand](https://cloudnative-pg.io/documentation/current/backup/#on-demand-backups)
+and
+[scheduled](https://cloudnative-pg.io/documentation/current/backup/#scheduled-backups)
+backups.
+
+To use the Barman Cloud Plugin, you must set the `method` to `plugin` and
+configure the `pluginConfiguration` section as shown:
+
+```yaml
+[...]
+spec:
+ method: plugin
+ pluginConfiguration:
+ name: barman-cloud.cloudnative-pg.io
+ [...]
+```
+
+With this configuration, CloudNativePG supports:
+
+- Backups from both **primary** and **standby** instances
+- Backups from **designated primaries** in a distributed topology using
+ [replica clusters](https://cloudnative-pg.io/documentation/current/replica_cluster/)
+
+:::tip
+For details on how to back up from a standby, refer to the official documentation:
+[Backup from a standby](https://cloudnative-pg.io/documentation/current/backup/#backup-from-a-standby).
+:::
+
+:::important
+Both backup and WAL archiving operations are executed by sidecar containers
+running in the same pod as the PostgreSQL `Cluster` primary instance—except
+when backups are taken from a standby, in which case the sidecar runs alongside
+the standby pod.
+The sidecar containers use a [dedicated container image](images.md) that
+includes only the supported version of Barman Cloud.
+:::
+
+## Recovery of a Postgres Cluster
+
+In PostgreSQL, *recovery* refers to the process of starting a database instance
+from an existing backup. The Barman Cloud Plugin integrates with CloudNativePG
+to support both **full recovery** and **Point-in-Time Recovery (PITR)** from an
+object store.
+
+Recovery in this context is *not in-place*: it bootstraps a brand-new
+PostgreSQL cluster from a backup and replays the necessary WAL files to reach
+the desired recovery target.
+
+To perform a recovery, define an *external cluster* that references the
+appropriate `ObjectStore`, and use it as the source in the `bootstrap` section
+of the target cluster:
+
+```yaml
+[...]
+spec:
+ [...]
+ bootstrap:
+ recovery:
+ source: source
+ externalClusters:
+ - name: source
+ plugin:
+ name: barman-cloud.cloudnative-pg.io
+ parameters:
+ barmanObjectName: cluster-example
+ serverName: cluster-example
+ [...]
+```
+
+The critical element here is the `externalClusters` section of the `Cluster`
+resource, where the `plugin` stanza instructs CloudNativePG to use the Barman
+Cloud Plugin to access the object store for recovery.
+
+This same mechanism can be used for a variety of scenarios enabled by the
+CloudNativePG API, including:
+
+* **Full cluster recovery** from the latest backup
+* **Point-in-Time Recovery (PITR)**
+* Bootstrapping **replica clusters** in a distributed topology
+
+:::tip
+For complete instructions and advanced use cases, refer to the official
+[Recovery documentation](https://cloudnative-pg.io/documentation/current/recovery/).
+:::
diff --git a/web/versioned_docs/version-0.12.0/images.md b/web/versioned_docs/version-0.12.0/images.md
new file mode 100644
index 0000000..f6c32d3
--- /dev/null
+++ b/web/versioned_docs/version-0.12.0/images.md
@@ -0,0 +1,37 @@
+---
+sidebar_position: 99
+---
+
+# Container Images
+
+
+
+The Barman Cloud Plugin is distributed using two container images:
+
+- One for deploying the plugin components
+- One for the sidecar that runs alongside each PostgreSQL instance in a
+ CloudNativePG `Cluster` using the plugin
+
+## Plugin Container Image
+
+The plugin image contains the logic required to operate the Barman Cloud Plugin
+within your Kubernetes environment with CloudNativePG. It is published on the
+GitHub Container Registry at `ghcr.io/cloudnative-pg/plugin-barman-cloud`.
+
+This image is built from the
+[`Dockerfile.plugin`](https://github.com/cloudnative-pg/plugin-barman-cloud/blob/main/containers/Dockerfile.plugin)
+in the plugin repository.
+
+## Sidecar Container Image
+
+The sidecar image is used within each PostgreSQL pod in the cluster. It
+includes the latest supported version of Barman Cloud and is responsible for
+performing WAL archiving and backups on behalf of CloudNativePG.
+
+It is available at `ghcr.io/cloudnative-pg/plugin-barman-cloud-sidecar` and is
+built from the
+[`Dockerfile.sidecar`](https://github.com/cloudnative-pg/plugin-barman-cloud/blob/main/containers/Dockerfile.sidecar).
+
+These sidecar images are designed to work seamlessly with the
+[`minimal` PostgreSQL container images](https://github.com/cloudnative-pg/postgres-containers?tab=readme-ov-file#minimal-images)
+maintained by the CloudNativePG Community.
diff --git a/web/versioned_docs/version-0.12.0/installation.mdx b/web/versioned_docs/version-0.12.0/installation.mdx
new file mode 100644
index 0000000..027d1e8
--- /dev/null
+++ b/web/versioned_docs/version-0.12.0/installation.mdx
@@ -0,0 +1,109 @@
+---
+sidebar_position: 20
+---
+
+# Installation
+
+:::important
+1. The plugin **must** be installed in the same namespace as the CloudNativePG
+ operator (typically `cnpg-system`).
+
+2. Keep in mind that the operator's **listening namespaces** may differ from its
+ installation namespace. Double-check this to avoid configuration issues.
+:::
+
+## Verifying the Requirements
+
+Before installing the plugin, make sure the [requirements](intro.md#requirements) are met.
+
+### CloudNativePG Version
+
+Ensure you're running a version of CloudNativePG that is compatible with the
+plugin. If installed in the default `cnpg-system` namespace, you can verify the
+version with:
+
+```sh
+kubectl get deployment -n cnpg-system cnpg-controller-manager \
+ -o jsonpath="{.spec.template.spec.containers[*].image}"
+```
+
+Example output:
+
+```output
+ghcr.io/cloudnative-pg/cloudnative-pg:1.26.0
+```
+
+The version **must be 1.26 or newer**.
+
+### cert-manager
+
+Use the [cmctl](https://cert-manager.io/docs/reference/cmctl/#installation)
+tool to confirm that `cert-manager` is installed and available:
+
+```sh
+cmctl check api
+```
+
+Example output:
+
+```output
+The cert-manager API is ready
+```
+
+Both checks are required before proceeding with the installation.
+
+## Installing the Barman Cloud Plugin
+
+import { InstallationSnippet } from '@site/src/components/Installation';
+
+Install the plugin using `kubectl` by applying the manifest for the latest
+release:
+
+