Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kubeseal for openSUSE:Factory checked in at 2026-08-28 19:51:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kubeseal (Old) and /work/SRC/openSUSE:Factory/.kubeseal.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kubeseal" Fri Aug 28 19:51:08 2026 rev:50 rq:1374257 version:0.39.1 Changes: -------- --- /work/SRC/openSUSE:Factory/kubeseal/kubeseal.changes 2026-07-03 16:11:50.859704402 +0200 +++ /work/SRC/openSUSE:Factory/.kubeseal.new.1265/kubeseal.changes 2026-08-28 19:52:34.761875837 +0200 @@ -1,0 +2,18 @@ +Fri Aug 28 07:23:23 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.39.1: + - Bump Golang to 1.26.6 (#2028) + - Bump Golang to 1.26.7 (#2029) + - Bump github.com/onsi/ginkgo/v2 from 2.32.0 to 2.32.1 (#2027) + - Bump golang.org/x/crypto from 0.54.0 to 0.55.0 (#2026) + - Release carvel package 2.19.2 (#2024) +- Update to version 0.39.0: + - Bump github.com/mattn/go-isatty from 0.0.22 to 0.0.23 (#2009) + - Bump github.com/mattn/go-isatty from 0.0.23 to 0.0.24 (#2011) + - Bump github.com/prometheus/client_golang from 1.23.2 to 1.24.1 + (#2016) + - Bump golang.org/x/crypto from 0.53.0 to 0.54.0 (#2007) + - Bump k8s.io/client-go from 0.36.2 to 0.36.3 (#2012) + - Bump k8s.io/code-generator from 0.36.2 to 0.36.3 (#2014) + +------------------------------------------------------------------- Old: ---- kubeseal-0.38.2.obscpio New: ---- kubeseal-0.39.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kubeseal.spec ++++++ --- /var/tmp/diff_new_pack.FnU8Mu/_old 2026-08-28 19:52:36.697943510 +0200 +++ /var/tmp/diff_new_pack.FnU8Mu/_new 2026-08-28 19:52:36.701943650 +0200 @@ -17,14 +17,14 @@ Name: kubeseal -Version: 0.38.2 +Version: 0.39.1 Release: 0 Summary: CLI for encrypting secrets to SealedSecrets License: Apache-2.0 URL: https://github.com/bitnami-labs/sealed-secrets Source: %{name}-%{version}.tar.gz Source1: vendor.tar.gz -BuildRequires: go1.26 >= 1.26.4 +BuildRequires: go1.26 >= 1.26.7 %description Problem: "I can manage all my K8s config in git, except Secrets." ++++++ _service ++++++ --- /var/tmp/diff_new_pack.FnU8Mu/_old 2026-08-28 19:52:36.794946900 +0200 +++ /var/tmp/diff_new_pack.FnU8Mu/_new 2026-08-28 19:52:36.808947390 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/bitnami-labs/sealed-secrets.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">refs/tags/v0.38.2</param> + <param name="revision">refs/tags/v0.39.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.FnU8Mu/_old 2026-08-28 19:52:36.870949557 +0200 +++ /var/tmp/diff_new_pack.FnU8Mu/_new 2026-08-28 19:52:36.877949802 +0200 @@ -3,6 +3,6 @@ <param name="url">https://github.com/bitnami-labs/sealed-secrets</param> <param name="changesrevision">97e5023c97fa29a5a91706c6d140851fa282bae7</param></service><service name="tar_scm"> <param name="url">https://github.com/bitnami-labs/sealed-secrets.git</param> - <param name="changesrevision">e88bf0ace0b5249d08623ea5cd203943549de7f3</param></service></servicedata> + <param name="changesrevision">af17f829e4647765d5c576837261bf44863c96cc</param></service></servicedata> (No newline at EOF) ++++++ kubeseal-0.38.2.obscpio -> kubeseal-0.39.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/RELEASE-NOTES.md new/kubeseal-0.39.1/RELEASE-NOTES.md --- old/kubeseal-0.38.2/RELEASE-NOTES.md 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/RELEASE-NOTES.md 2026-08-20 10:43:03.000000000 +0200 @@ -4,6 +4,37 @@ [](https://github.com/bitnami/sealed-secrets/releases/latest) +## v0.39.1 + +- Bump Golang to 1.26.7 ([#2029](https://github.com/bitnami/sealed-secrets/pull/2029)) +- Bump Golang to 1.26.6 ([#2028](https://github.com/bitnami/sealed-secrets/pull/2028)) +- Bump golang.org/x/crypto from 0.54.0 to 0.55.0 ([#2026](https://github.com/bitnami/sealed-secrets/pull/2026)) +- Bump github.com/onsi/ginkgo/v2 from 2.32.0 to 2.32.1 ([#2027](https://github.com/bitnami/sealed-secrets/pull/2027)) +- test(controller): fix flaky TestReadKey RSA key comparison ([#2021](https://github.com/bitnami/sealed-secrets/pull/2021)) + +## v0.39.0 + +- [Security] fix: stop /v1/verify from acting as a decryption oracle ([#2019](https://github.com/bitnami/sealed-secrets/pull/2019)) +- fix(controller): start HTTP early for large additional-namespaces lists ([#2018](https://github.com/bitnami/sealed-secrets/pull/2018)) +- Rate-limit the /v1/rotate endpoint ([#1971](https://github.com/bitnami/sealed-secrets/pull/1971)) +- test(controller): poll for server readiness instead of sleeping ([#2010](https://github.com/bitnami/sealed-secrets/pull/2010)) +- Bump github.com/prometheus/client_golang from 1.23.2 to 1.24.1 ([#2016](https://github.com/bitnami/sealed-secrets/pull/2016)) +- Bump k8s.io/code-generator from 0.36.2 to 0.36.3 ([#2014](https://github.com/bitnami/sealed-secrets/pull/2014)) +- Bump github.com/mattn/go-isatty from 0.0.23 to 0.0.24 ([#2011](https://github.com/bitnami/sealed-secrets/pull/2011)) +- Bump k8s.io/client-go from 0.36.2 to 0.36.3 ([#2012](https://github.com/bitnami/sealed-secrets/pull/2012)) +- Bump github.com/mattn/go-isatty from 0.0.22 to 0.0.23 ([#2009](https://github.com/bitnami/sealed-secrets/pull/2009)) +- Bump golang.org/x/crypto from 0.53.0 to 0.54.0 ([#2007](https://github.com/bitnami/sealed-secrets/pull/2007)) +- Bump distroless/static from `3592aa8` to `9197324` in /docker ([#2008](https://github.com/bitnami/sealed-secrets/pull/2008)) +- Allow setting hostUsers on deployment ([#1978](https://github.com/bitnami/sealed-secrets/pull/1978)) +- Add --metrics-omit-secret-labels to skip per-SealedSecret labels on condition_info ([#1972](https://github.com/bitnami/sealed-secrets/pull/1972)) +- Revert ArtifactHub repository metadata OCI push ([#2005](https://github.com/bitnami/sealed-secrets/pull/2005)) + +## v0.38.4 +- Incomplete release for credentials problems + +## v0.38.3 +- Imcomplete release for credentials problems + ## v0.38.2 - Publish Artifact Hub repository metadata for verified publisher status ([#2000](https://github.com/bitnami/sealed-secrets/pull/2000)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/carvel/package.yaml new/kubeseal-0.39.1/carvel/package.yaml --- old/kubeseal-0.38.2/carvel/package.yaml 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/carvel/package.yaml 2026-08-20 10:43:03.000000000 +0200 @@ -1,10 +1,10 @@ apiVersion: data.packaging.carvel.dev/v1alpha1 kind: Package metadata: - name: "sealedsecrets.bitnami.com.2.19.0" + name: "sealedsecrets.bitnami.com.2.19.2" spec: refName: "sealedsecrets.bitnami.com" - version: "2.19.0" + version: "2.19.2" valuesSchema: openAPIv3: title: Chart Values @@ -424,7 +424,7 @@ spec: fetch: - imgpkgBundle: - image: ghcr.io/bitnami/sealed-secrets-carvel@sha256:71d0dcedd1d3d0659e8656f7b0799a02d7c40f5e0c7df6acab701779690b49a6 + image: ghcr.io/bitnami/sealed-secrets-carvel@sha256:e835d919d5d1a832121a538daef097cd8dfbb6cfbca131f45a723113b1f915d0 template: - helmTemplate: path: sealed-secrets diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/cmd/controller/main.go new/kubeseal-0.39.1/cmd/controller/main.go --- old/kubeseal-0.38.2/cmd/controller/main.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/cmd/controller/main.go 2026-08-20 10:43:03.000000000 +0200 @@ -43,14 +43,15 @@ fs.BoolVar(&f.NamespaceAll, "all-namespaces", true, "Scan all namespaces or only the current namespace (default=true).") fs.StringVar(&f.AdditionalNamespaces, "additional-namespaces", "", "Comma-separated list of additional namespaces to be scanned.") fs.StringVar(&f.LabelSelector, "label-selector", "", "Label selector which can be used to filter sealed secrets.") - fs.IntVar(&f.RateLimitPerSecond, "rate-limit", 2, "Number of allowed sustained request per second for verify endpoint") - fs.IntVar(&f.RateLimitBurst, "rate-limit-burst", 2, "Number of requests allowed to exceed the rate limit per second for verify endpoint") + fs.IntVar(&f.RateLimitPerSecond, "rate-limit", 2, "Number of allowed sustained requests per second for the verify and rotate endpoints") + fs.IntVar(&f.RateLimitBurst, "rate-limit-burst", 2, "Number of requests allowed to exceed the rate limit per second for the verify and rotate endpoints") + fs.BoolVar(&f.MetricsOmitSecretLabels, "metrics-omit-secret-labels", false, "When true, the sealed_secrets_controller_condition_info metric is not updated, so the metrics endpoint does not expose SealedSecret namespaces and names. Use this if :8081 is reachable by users who should not be able to enumerate SealedSecret inventory.") fs.StringVar(&f.PrivateKeyAnnotations, "privatekey-annotations", "", "Comma-separated list of additional annotations to be put on renewed sealing keys.") fs.StringVar(&f.PrivateKeyLabels, "privatekey-labels", "", "Comma-separated list of additional labels to be put on renewed sealing keys.") fs.BoolVar(&f.OldGCBehavior, "old-gc-behavior", false, "Revert to old GC behavior where the controller deletes secrets instead of delegating that to k8s itself.") - fs.BoolVar(&f.UpdateStatus, "update-status", true, "beta: if true, the controller will update the status sub-resource whenever it processes a sealed secret") + fs.BoolVar(&f.UpdateStatus, "update-status", true, "if true, the controller will update the status sub-resource whenever it processes a sealed secret (stable; enabled by default since v0.17.0)") fs.BoolVar(&f.WatchForSecrets, "watch-for-secrets", false, "beta: If this is true, the controller will watch for key secrets. This is useful if you create the key secrets externally.") fs.BoolVar(&f.SkipRecreate, "skip-recreate", false, "if true the controller will skip listening for managed secret changes to recreate them. This helps on limited permission environments.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/docker/controller.Dockerfile new/kubeseal-0.39.1/docker/controller.Dockerfile --- old/kubeseal-0.38.2/docker/controller.Dockerfile 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/docker/controller.Dockerfile 2026-08-20 10:43:03.000000000 +0200 @@ -1,4 +1,4 @@ -FROM gcr.io/distroless/static@sha256:3592aa8171c77482f62bbc4164e6a2d141c6122554ace66e5cc910cadb961ff0 +FROM gcr.io/distroless/static@sha256:9197324ba51d9cd071af8505989365c006adf9d6d2067eada25aef00abbb5278 LABEL maintainer "Sealed Secrets <[email protected]>" USER 1001 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/docker/kubeseal.Dockerfile new/kubeseal-0.39.1/docker/kubeseal.Dockerfile --- old/kubeseal-0.38.2/docker/kubeseal.Dockerfile 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/docker/kubeseal.Dockerfile 2026-08-20 10:43:03.000000000 +0200 @@ -1,4 +1,4 @@ -FROM gcr.io/distroless/static@sha256:3592aa8171c77482f62bbc4164e6a2d141c6122554ace66e5cc910cadb961ff0 +FROM gcr.io/distroless/static@sha256:9197324ba51d9cd071af8505989365c006adf9d6d2067eada25aef00abbb5278 LABEL maintainer "Sealed Secrets <[email protected]>" USER 1001 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/go.mod new/kubeseal-0.39.1/go.mod --- old/kubeseal-0.38.2/go.mod 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/go.mod 2026-08-20 10:43:03.000000000 +0200 @@ -1,25 +1,25 @@ module github.com/bitnami/sealed-secrets -go 1.26.4 +go 1.26.7 require ( github.com/Masterminds/sprig/v3 v3.3.0 github.com/google/go-cmp v0.7.0 github.com/google/renameio v0.1.0 - github.com/mattn/go-isatty v0.0.22 + github.com/mattn/go-isatty v0.0.24 github.com/mkmik/multierror v0.4.0 - github.com/onsi/ginkgo/v2 v2.32.0 + github.com/onsi/ginkgo/v2 v2.32.1 github.com/onsi/gomega v1.42.1 - github.com/prometheus/client_golang v1.23.2 + github.com/prometheus/client_golang v1.24.1 github.com/prometheus/client_model v0.6.2 github.com/spf13/pflag v1.0.10 github.com/throttled/throttled v2.2.5+incompatible - golang.org/x/crypto v0.53.0 + golang.org/x/crypto v0.55.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.36.2 - k8s.io/apimachinery v0.36.2 - k8s.io/client-go v0.36.2 - k8s.io/code-generator v0.36.2 + k8s.io/api v0.36.3 + k8s.io/apimachinery v0.36.3 + k8s.io/client-go v0.36.3 + k8s.io/code-generator v0.36.3 k8s.io/klog v1.0.0 k8s.io/klog/v2 v2.140.0 ) @@ -53,22 +53,22 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.70.1 // indirect + github.com/prometheus/procfs v0.21.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.36.0 // indirect - golang.org/x/net v0.56.0 // indirect - golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.38.0 // indirect + golang.org/x/mod v0.38.0 // indirect + golang.org/x/net v0.57.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.41.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.45.0 // indirect + golang.org/x/tools v0.48.0 // 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 @@ -78,6 +78,6 @@ k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // 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 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.3 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/go.sum new/kubeseal-0.39.1/go.sum --- old/kubeseal-0.38.2/go.sum 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/go.sum 2026-08-20 10:43:03.000000000 +0200 @@ -62,8 +62,8 @@ github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= +github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -74,8 +74,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= -github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -92,21 +92,21 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.32.0 h1:Hw7s2pVrQo/8Yz5N77qdnpHaoc+c6cC9WIV1Jce+J6E= -github.com/onsi/ginkgo/v2 v2.32.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= +github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw= +github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU= +github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE= 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.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi/PY= +github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc= +github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= +github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= @@ -135,30 +135,30 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -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.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/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= -golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= -golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= -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.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +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.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= 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.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= -golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -176,14 +176,14 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= -k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= -k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= -k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= -k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI= -k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0= -k8s.io/code-generator v0.36.2 h1:iBNFYhClojQaVrF99Z3iTAad7LztQh3yCtwR8L8Ocpg= -k8s.io/code-generator v0.36.2/go.mod h1:IfnsRW1IAq9iPxqs/FfOnVnWWONxS2mPDvWNR4fPlzI= +k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w= +k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg= +k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= +k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= +k8s.io/client-go v0.36.3 h1:M4JdVzXxYcZk4fGpfDdYnxSwhLKWCFoQsHW6t+z8Hfg= +k8s.io/client-go v0.36.3/go.mod h1:gcPwr0c87vjjG6HB6pWEqOeuYVoXSsREjzux2j6GF30= +k8s.io/code-generator v0.36.3 h1:tsiHI6NepXQncnexlTAf52w5VxZ4HYDU4ZqCNLFb9tA= +k8s.io/code-generator v0.36.3/go.mod h1:Unn13Mp8X+H803jgZi4f4ExxK11aj0llXcSsl++UTkE= k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= @@ -198,7 +198,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= 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 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3 h1:u08YRbVUi59ri4YD6cg0UqNM4Dimn0sIl+wldcx5PYw= +sigs.k8s.io/structured-merge-diff/v6 v6.3.3/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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/helm/sealed-secrets/Chart.yaml new/kubeseal-0.39.1/helm/sealed-secrets/Chart.yaml --- old/kubeseal-0.38.2/helm/sealed-secrets/Chart.yaml 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/helm/sealed-secrets/Chart.yaml 2026-08-20 10:43:03.000000000 +0200 @@ -1,7 +1,7 @@ annotations: category: DeveloperTools apiVersion: v2 -appVersion: 0.38.1 +appVersion: 0.39.0 description: Helm chart for the sealed-secrets controller. home: https://github.com/bitnami/sealed-secrets icon: https://bitnami.com/assets/stacks/sealed-secrets/img/sealed-secrets-stack-220x234.png @@ -14,6 +14,6 @@ url: https://github.com/bitnami/sealed-secrets name: sealed-secrets type: application -version: 2.19.0 +version: 2.19.2 sources: - https://github.com/bitnami/sealed-secrets diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/helm/sealed-secrets/README.md new/kubeseal-0.39.1/helm/sealed-secrets/README.md --- old/kubeseal-0.38.2/helm/sealed-secrets/README.md 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/helm/sealed-secrets/README.md 2026-08-20 10:43:03.000000000 +0200 @@ -88,7 +88,7 @@ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------- | | `image.registry` | Sealed Secrets image registry | `docker.io` | | `image.repository` | Sealed Secrets image repository | `bitnami/sealed-secrets-controller` | -| `image.tag` | Sealed Secrets image tag (immutable tags are recommended) | `0.38.1` | +| `image.tag` | Sealed Secrets image tag (immutable tags are recommended) | `0.39.0` | | `image.pullPolicy` | Sealed Secrets image pull policy | `IfNotPresent` | | `image.pullSecrets` | Sealed Secrets image pull secrets | `[]` | | `revisionHistoryLimit` | Number of old history to retain to allow rollback (If not set, default Kubernetes value is set to 10) | `""` | @@ -145,6 +145,7 @@ | `containerSecurityContext.runAsUser` | Set Sealed Secret containers' Security Context runAsUser | `1001` | | `containerSecurityContext.allowPrivilegeEscalation` | Set Sealed Secret containers' privilege escalation | `false` | | `containerSecurityContext.capabilities` | Adds and removes POSIX capabilities from running containers (see `values.yaml`) | | +| `hostUsers` | Specifies whether or not host or namespaced users should be used | `null` | | `podLabels` | Extra labels for Sealed Secret pods | `{}` | | `podAnnotations` | Annotations for Sealed Secret pods | `{}` | | `priorityClassName` | Sealed Secret pods' priorityClassName | `""` | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/helm/sealed-secrets/templates/deployment.yaml new/kubeseal-0.39.1/helm/sealed-secrets/templates/deployment.yaml --- old/kubeseal-0.38.2/helm/sealed-secrets/templates/deployment.yaml 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/helm/sealed-secrets/templates/deployment.yaml 2026-08-20 10:43:03.000000000 +0200 @@ -54,6 +54,9 @@ securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} {{- end }} serviceAccountName: {{ include "sealed-secrets.serviceAccountName" . }} + {{- if kindIs "bool" .Values.hostUsers }} + hostUsers: {{ .Values.hostUsers }} + {{- end }} {{- if .Values.hostNetwork }} hostNetwork: true {{- end }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/helm/sealed-secrets/values.yaml new/kubeseal-0.39.1/helm/sealed-secrets/values.yaml --- old/kubeseal-0.38.2/helm/sealed-secrets/values.yaml 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/helm/sealed-secrets/values.yaml 2026-08-20 10:43:03.000000000 +0200 @@ -39,7 +39,7 @@ image: registry: docker.io repository: bitnami/sealed-secrets-controller - tag: 0.38.1 + tag: 0.39.0 ## Specify a imagePullPolicy ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images @@ -221,6 +221,10 @@ capabilities: drop: - ALL +## @param hostUsers Specifies whether or not host or namespaced users should be used +## ref: https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/ +## +hostUsers: ~ ## @param podLabels [object] Extra labels for Sealed Secret pods ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_expansion.go new/kubeseal-0.39.1/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_expansion.go --- old/kubeseal-0.38.2/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_expansion.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_expansion.go 2026-08-20 10:43:03.000000000 +0200 @@ -262,6 +262,36 @@ return s, nil } +// ValidateEncryptedData checks decryptability without rendering spec.template.data. +func (s *SealedSecret) ValidateEncryptedData(privKeys map[string]*rsa.PrivateKey) error { + label := labelFor(s.GetObjectMeta()) + + if s.Spec.Data == nil { + var errs []error + for key, value := range s.Spec.EncryptedData { + valueBytes, err := base64.StdEncoding.DecodeString(value) + if err != nil { + errs = append(errs, multierror.Tag(key, err)) + continue + } + if _, err := crypto.HybridDecrypt(rand.Reader, privKeys, valueBytes, label); err != nil { + errs = append(errs, multierror.Tag(key, err)) + } + } + if errs != nil { + return multierror.Format(errors.Join(multierror.Uniq(errs)...), multierror.InlineFormatter) + } + return nil + } else if AcceptDeprecatedV1Data { // Support decrypting old secrets for backward compatibility + if len(s.Spec.EncryptedData) > 0 { + return fmt.Errorf("cannot use the field 'encryptedData' and the deprecated field 'data' at the same time") + } + _, err := crypto.HybridDecrypt(rand.Reader, privKeys, s.Spec.Data, label) + return err + } + return fmt.Errorf("using deprecated 'data' field, use 'encryptedData' or flip the feature flag") +} + // Unseal decrypts and returns the embedded v1.Secret. func (s *SealedSecret) Unseal(codecs runtimeserializer.CodecFactory, privKeys map[string]*rsa.PrivateKey) (*v1.Secret, error) { boolTrue := true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_test.go new/kubeseal-0.39.1/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_test.go --- old/kubeseal-0.38.2/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_test.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_test.go 2026-08-20 10:43:03.000000000 +0200 @@ -391,6 +391,43 @@ } } +// TestValidateEncryptedDataIgnoresTemplate ensures template execution can't affect decryptability checks. +func TestValidateEncryptedDataIgnoresTemplate(t *testing.T) { + secret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myname", + Namespace: "myns", + }, + Data: map[string][]byte{ + "password": []byte("hunter2"), + }, + } + + ssecret, _, keys := sealSecret(t, &secret, NewSealedSecret) + + // A failing template must not turn a decryptable secret into a validation failure. + ssecret.Spec.Template.Data = map[string]string{ + "probe": `{{ fail "attacker-controlled failure" }}`, + } + if err := ssecret.ValidateEncryptedData(keys); err != nil { + t.Errorf("ValidateEncryptedData returned error for a decryptable secret with a failing template: %v", err) + } + + // A template with a parse error must likewise not affect the result. + ssecret.Spec.Template.Data = map[string]string{ + "probe": `{{ .password`, + } + if err := ssecret.ValidateEncryptedData(keys); err != nil { + t.Errorf("ValidateEncryptedData returned error for a decryptable secret with an unparseable template: %v", err) + } + + // Sanity check: genuinely undecryptable data must still fail. + _, otherKeys := generateTestKey(t, testRand(), 2048) + if err := ssecret.ValidateEncryptedData(otherKeys); err == nil { + t.Errorf("ValidateEncryptedData did not return an error for encryptedData undecryptable with the given keys") + } +} + // TestTemplateDataPlaintextReference verifies that plaintext keys defined // in spec.template.data can be referenced from sibling templates as // {{ .key }} variables. Regression test for diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/controller.go new/kubeseal-0.39.1/pkg/controller/controller.go --- old/kubeseal-0.38.2/pkg/controller/controller.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/controller.go 2026-08-20 10:43:03.000000000 +0200 @@ -534,7 +534,7 @@ return fmt.Sprintf("Error updating %s: the target Secret is immutable. Once a Secret is marked as immutable, it is not possible to revert this change nor to mutate the contents of the data field. You can only delete and recreate the Secret.", key) } -// AttemptUnseal tries to unseal a secret. +// AttemptUnseal checks whether a secret is decryptable, without rendering spec.template.data. func (c *Controller) AttemptUnseal(content []byte) (bool, error) { if err := multidocyaml.EnsureNotMultiDoc(content); err != nil { return false, err @@ -547,7 +547,7 @@ switch s := object.(type) { case *ssv1alpha1.SealedSecret: - if _, err := c.attemptUnseal(s); err != nil { + if err := s.ValidateEncryptedData(c.keyRegistry.privateKeys()); err != nil { return false, nil } return true, nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/controller_test.go new/kubeseal-0.39.1/pkg/controller/controller_test.go --- old/kubeseal-0.38.2/pkg/controller/controller_test.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/controller_test.go 2026-08-20 10:43:03.000000000 +0200 @@ -398,3 +398,71 @@ t.Fatalf("Scope from the original and the rotate sealed secret do not match") } } + +// TestAttemptUnsealIgnoresTemplate is a regression test for the /v1/verify decryption oracle. +func TestAttemptUnsealIgnoresTemplate(t *testing.T) { + ns := "some-namespace" + keyNs := "some-key-namespace" + var tweakopts func(*metav1.ListOptions) + clientset := fake.NewClientset() + ssc := ssfake.NewSimpleClientset() + keyRegistry := testKeyRegister(t, context.Background(), clientset, ns) + + validFor := time.Hour + cn := "my-cn" + _, err := keyRegistry.generateKey(context.Background(), validFor, cn, "", "") + if err != nil { + t.Fatal(err) + } + + controller, err := prepareController(clientset, ns, keyNs, tweakopts, &Flags{SkipRecreate: false}, ssc, keyRegistry) + if err != nil { + t.Fatalf("err %v want %v", err, nil) + } + + secret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "ss", + Namespace: "default", + }, + Data: map[string][]byte{ + "password": []byte("hunter2"), + }, + } + + cert, err := controller.keyRegistry.getCert() + if err != nil { + t.Fatalf("error getting certificate: %v", err) + } + + ssecret, err := ssv1alpha1.NewSealedSecret(scheme.Codecs, cert.PublicKey.(*rsa.PublicKey), secret) + if err != nil { + t.Fatalf("error creating sealed secrets: %v", err) + } + + // Attacker-controlled, always-failing template paired with the victim's real data. + ssecret.Spec.Template.Data = map[string]string{ + "probe": `{{ fail "attacker-controlled failure" }}`, + } + + enc, err := prettyEncoder(scheme.Codecs, runtime.ContentTypeJSON, ssv1alpha1.SchemeGroupVersion) + if err != nil { + t.Fatalf("unexpected pretty encoding: %v", err) + } + data, err := runtime.Encode(enc, ssecret) + if err != nil { + t.Fatalf("unexpected encoding the sealed secret: %v", err) + } + + valid, err := controller.AttemptUnseal(data) + if err != nil { + t.Fatalf("AttemptUnseal returned error: %v", err) + } + if !valid { + t.Errorf("AttemptUnseal reported a decryptable secret as invalid because of an unrelated template failure") + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/keys_test.go new/kubeseal-0.39.1/pkg/controller/keys_test.go --- old/kubeseal-0.38.2/pkg/controller/keys_test.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/keys_test.go 2026-08-20 10:43:03.000000000 +0200 @@ -7,7 +7,6 @@ "encoding/pem" "io" mathrand "math/rand" - "reflect" "strings" "testing" "time" @@ -65,11 +64,15 @@ t.Errorf("readKey() failed with: %v", err) } - if !reflect.DeepEqual(key, key2) { + // Use crypto value equality, not reflect.DeepEqual: rsa.PrivateKey embeds + // PrecomputedValues with unexported sync/once state that differs between a + // freshly generated key and one re-parsed from PEM, which made this test + // flaky under CI (see #1903). + if !key.Equal(key2) { t.Errorf("Extracted key != original key") } - if !reflect.DeepEqual(cert, cert2[0]) { + if len(cert2) == 0 || !cert.Equal(cert2[0]) { t.Errorf("Extracted cert != original cert") } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/main.go new/kubeseal-0.39.1/pkg/controller/main.go --- old/kubeseal-0.38.2/pkg/controller/main.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/main.go 2026-08-20 10:43:03.000000000 +0200 @@ -10,6 +10,8 @@ "os/signal" "sort" "strings" + "sync" + "sync/atomic" "syscall" "time" @@ -28,6 +30,11 @@ ssinformers "github.com/bitnami/sealed-secrets/pkg/client/informers/externalversions" ) +// Cap concurrent namespace Gets and informer setup so a large +// --additional-namespaces list does not serialize one RTT per namespace +// and does not stampede the API server either. +const additionalNamespaceBootstrapConcurrency = 16 + var ( // Selector used to find existing public/private key pairs on startup. keySelector = fields.OneTermEqualSelector(SealedSecretsKeyLabel, "active") @@ -35,31 +42,32 @@ // Flags to configure the controller. type Flags struct { - KeyPrefix string - KeySize int - ValidFor time.Duration - MyCN string - KeyRenewPeriod time.Duration - KeyOrderPriority string - AcceptV1Data bool - KeyCutoffTime string - NamespaceAll bool - AdditionalNamespaces string - LabelSelector string - RateLimitPerSecond int - RateLimitBurst int - OldGCBehavior bool - UpdateStatus bool - SkipRecreate bool - LogInfoToStdout bool - LogLevel string - LogFormat string - PrivateKeyAnnotations string - PrivateKeyLabels string - MaxRetries int - WatchForSecrets bool - KubeClientQPS float32 - KubeClientBurst int + KeyPrefix string + KeySize int + ValidFor time.Duration + MyCN string + KeyRenewPeriod time.Duration + KeyOrderPriority string + AcceptV1Data bool + KeyCutoffTime string + NamespaceAll bool + AdditionalNamespaces string + LabelSelector string + RateLimitPerSecond int + RateLimitBurst int + MetricsOmitSecretLabels bool + OldGCBehavior bool + UpdateStatus bool + SkipRecreate bool + LogInfoToStdout bool + LogLevel string + LogFormat string + PrivateKeyAnnotations string + PrivateKeyLabels string + MaxRetries int + WatchForSecrets bool + KubeClientQPS float32 + KubeClientBurst int } func initKeyPrefix(keyPrefix string) (string, error) { @@ -174,6 +182,7 @@ } func Main(f *Flags, version string) error { + SetMetricsOmitSecretLabels(f.MetricsOmitSecretLabels) registerMetrics(version) config, err := rest.InClusterConfig() @@ -248,30 +257,9 @@ go controller.Run(stop) - if f.AdditionalNamespaces != "" { - addNS := removeDuplicates(strings.Split(f.AdditionalNamespaces, ",")) - - for _, ns := range addNS { - if _, err := clientset.CoreV1().Namespaces().Get(ctx, ns, metav1.GetOptions{}); err != nil { - if errors.IsNotFound(err) { - slog.Error("namespace doesn't exist", "namespace", ns) - continue - } - return err - } - if ns != namespace { - ctlr, err := prepareController(clientset, ns, myNs, tweakopts, f, ssclientset, keyRegistry) - if err != nil { - return err - } - ctlr.oldGCBehavior = f.OldGCBehavior - ctlr.updateStatus = f.UpdateStatus - slog.Info("Starting informer", "namespace", ns) - go ctlr.Run(stop) - } - } - } - + // ready becomes true after additional-namespace informers are started. + // HTTP must come up first so liveness probes succeed during that work. + var bootstrapped atomic.Bool cp := func() ([]*x509.Certificate, error) { cert, err := keyRegistry.getCert() if err != nil { @@ -279,10 +267,24 @@ } return []*x509.Certificate{cert}, nil } - - server := httpserver(cp, controller.AttemptUnseal, controller.Rotate, f.RateLimitBurst, f.RateLimitPerSecond) + server := httpserver(cp, controller.AttemptUnseal, controller.Rotate, f.RateLimitBurst, f.RateLimitPerSecond, bootstrapped.Load) serverMetrics := httpserverMetrics() + if f.AdditionalNamespaces != "" { + addNS := removeDuplicates(strings.Split(f.AdditionalNamespaces, ",")) + // Bind ctx to the namespace probe here so the bootstrap helper does not + // take a context parameter (contextcheck would otherwise require + // prepareController/Run to accept one; those still use stopCh lifecycle). + probeNS := func(ns string) error { + _, err := clientset.CoreV1().Namespaces().Get(ctx, ns, metav1.GetOptions{}) + return err + } + if err := startAdditionalNamespaceControllers(probeNS, clientset, ssclientset, keyRegistry, f, namespace, myNs, tweakopts, addNS, stop); err != nil { + return err + } + } + bootstrapped.Store(true) + sigterm := make(chan os.Signal, 1) signal.Notify(sigterm, syscall.SIGTERM) <-sigterm @@ -298,6 +300,74 @@ return nil } +// startAdditionalNamespaceControllers validates and starts a controller for each +// extra namespace. Work is bounded-parallel so wall-clock startup scales better +// than one serial API Get per namespace. +// +// probeNS should check that ns exists (typically clientset Get with the caller's +// context). Missing namespaces are logged and skipped; other probe errors abort. +func startAdditionalNamespaceControllers( + probeNS func(ns string) error, + clientset kubernetes.Interface, + ssclientset versioned.Interface, + keyRegistry *KeyRegistry, + f *Flags, + homeNamespace string, + keyNamespace string, + tweakopts func(*metav1.ListOptions), + namespaces []string, + stop <-chan struct{}, +) error { + sem := make(chan struct{}, additionalNamespaceBootstrapConcurrency) + var wg sync.WaitGroup + var mu sync.Mutex + var firstErr error + + setErr := func(err error) { + if err == nil { + return + } + mu.Lock() + if firstErr == nil { + firstErr = err + } + mu.Unlock() + } + + for _, ns := range namespaces { + ns := strings.TrimSpace(ns) + if ns == "" || ns == homeNamespace { + continue + } + wg.Add(1) + go func(ns string) { + defer wg.Done() + sem <- struct{}{} + defer func() { <-sem }() + + if err := probeNS(ns); err != nil { + if errors.IsNotFound(err) { + slog.Error("namespace doesn't exist", "namespace", ns) + return + } + setErr(err) + return + } + ctlr, err := prepareController(clientset, ns, keyNamespace, tweakopts, f, ssclientset, keyRegistry) + if err != nil { + setErr(err) + return + } + ctlr.oldGCBehavior = f.OldGCBehavior + ctlr.updateStatus = f.UpdateStatus + slog.Info("Starting informer", "namespace", ns) + go ctlr.Run(stop) + }(ns) + } + wg.Wait() + return firstErr +} + func prepareController( clientset kubernetes.Interface, namespace string, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/metrics.go new/kubeseal-0.39.1/pkg/controller/metrics.go --- old/kubeseal-0.38.2/pkg/controller/metrics.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/metrics.go 2026-08-20 10:43:03.000000000 +0200 @@ -13,6 +13,17 @@ // Define Prometheus Exporter namespace (prefix) for all metric names. const metricNamespace string = "sealed_secrets_controller" +// metricsOmitSecretLabels controls whether ObserveCondition and +// UnregisterCondition emit per-SealedSecret labels on condition_info. +// When true the gauge is not updated at all, so the metrics endpoint +// no longer exposes an inventory of SealedSecret namespaces and names +// to anyone who can reach :8081. +var metricsOmitSecretLabels bool + +// SetMetricsOmitSecretLabels wires the controller flag into the metrics +// package. Called once from controller.Main before registerMetrics. +func SetMetricsOmitSecretLabels(b bool) { metricsOmitSecretLabels = b } + const ( labelNamespace = "namespace" labelName = "name" @@ -98,6 +109,9 @@ // ObserveCondition sets a `condition_info` Gauge according to a SealedSecret status. func ObserveCondition(ssecret *v1alpha1.SealedSecret) { + if metricsOmitSecretLabels { + return + } if ssecret.Status == nil { return } @@ -113,6 +127,9 @@ // UnregisterCondition unregisters Gauges associated to a SealedSecret conditions. func UnregisterCondition(ssecret *v1alpha1.SealedSecret) { + if metricsOmitSecretLabels { + return + } if ssecret.Status == nil { return } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/metrics_test.go new/kubeseal-0.39.1/pkg/controller/metrics_test.go --- old/kubeseal-0.38.2/pkg/controller/metrics_test.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/metrics_test.go 2026-08-20 10:43:03.000000000 +0200 @@ -230,3 +230,33 @@ } return "" } + +func TestObserveConditionRespectsOmitSecretLabels(t *testing.T) { + registry := setupTestMetrics() + SetMetricsOmitSecretLabels(true) + t.Cleanup(func() { SetMetricsOmitSecretLabels(false) }) + + ssecret := &ssv1alpha1.SealedSecret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-ns", + Name: "test-secret", + }, + Status: &ssv1alpha1.SealedSecretStatus{ + Conditions: []ssv1alpha1.SealedSecretCondition{ + {Type: ssv1alpha1.SealedSecretSynced, Status: corev1.ConditionTrue}, + }, + }, + } + + ObserveCondition(ssecret) + + metricFamilies, err := registry.Gather() + if err != nil { + t.Fatalf("Failed to gather metrics: %v", err) + } + for _, mf := range metricFamilies { + if mf.GetName() == "sealed_secrets_controller_condition_info" && len(mf.GetMetric()) > 0 { + t.Errorf("Expected condition_info to be empty when omit flag is on, got %d series", len(mf.GetMetric())) + } + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/server.go new/kubeseal-0.39.1/pkg/controller/server.go --- old/kubeseal-0.38.2/pkg/controller/server.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/server.go 2026-08-20 10:43:03.000000000 +0200 @@ -29,11 +29,20 @@ type secretChecker func([]byte) (bool, error) type secretRotator func([]byte) ([]byte, error) +// readyFunc reports whether controller bootstrap finished (informers for the +// home namespace and any --additional-namespaces have been started). +// A nil readyFunc treats the process as always ready. +type readyFunc func() bool + // httpserver starts an HTTP that exposes core functionality like serving the public key // or secret rotation and validation. This endpoint is designed to be accessible by // all users of a given cluster. It must not leak any secret material. // The server is started in the background and a handle to it returned so it can be shut down. -func httpserver(cp certProvider, sc secretChecker, sr secretRotator, burst int, rate int) *http.Server { +// +// /healthz is a liveness probe: it always succeeds once the listener is up so the +// process is not killed while additional namespace informers are still starting. +// /readyz is a readiness probe: it returns 503 until ready reports true. +func httpserver(cp certProvider, sc secretChecker, sr secretRotator, burst int, rate int, ready readyFunc) *http.Server { httpRateLimiter := rateLimiter(burst, rate) mux := http.NewServeMux() @@ -46,6 +55,19 @@ } }) + mux.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + if ready != nil && !ready() { + w.WriteHeader(http.StatusServiceUnavailable) + _, _ = io.WriteString(w, "not ready\n") + return + } + _, err := io.WriteString(w, "ok\n") + if err != nil { + log.Fatal(err) + } + }) + mux.Handle("/v1/verify", Instrument("/v1/verify", httpRateLimiter.RateLimit(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { content, err := io.ReadAll(r.Body) if err != nil { @@ -69,7 +91,7 @@ })))) // TODO(mkm): rename to re-encrypt - mux.Handle("/v1/rotate", Instrument("/v1/rotate", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mux.Handle("/v1/rotate", Instrument("/v1/rotate", httpRateLimiter.RateLimit(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { content, err := io.ReadAll(r.Body) if err != nil { slog.Error("Error handling /v1/rotate request", "error", err) @@ -87,7 +109,7 @@ w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") _, _ = w.Write(newSecret) - }))) + })))) mux.Handle("/v1/cert.pem", Instrument("/v1/cert.pem", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { certs, err := cp() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/pkg/controller/server_test.go new/kubeseal-0.39.1/pkg/controller/server_test.go --- old/kubeseal-0.38.2/pkg/controller/server_test.go 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/pkg/controller/server_test.go 2026-08-20 10:43:03.000000000 +0200 @@ -5,6 +5,7 @@ "crypto/x509" "fmt" "io" + "net" "net/http" "strings" "sync" @@ -38,6 +39,28 @@ } } +// waitForServer polls addr until the server is accepting TCP connections, +// failing the test if it is not ready within a short deadline. This replaces +// a fixed sleep so the test proceeds as soon as the server is up and does not +// flake under load when startup takes longer than the sleep. It dials the +// socket rather than issuing an HTTP request so it does not exercise the +// handler before the test has populated the cert store. +func waitForServer(t *testing.T, addr string) { + t.Helper() + deadline := time.Now().Add(10 * time.Second) + for { + conn, err := net.DialTimeout("tcp", addr, 100*time.Millisecond) + if err == nil { + conn.Close() + return + } + if time.Now().After(deadline) { + t.Fatalf("server did not start listening on %s: %v", addr, err) + } + time.Sleep(10 * time.Millisecond) + } +} + func TestHttpCert(t *testing.T) { validFor := time.Hour cn := "my-cn" @@ -52,14 +75,16 @@ } cs := &testCertStore{} - server := httpserver(cs.getCert, nil, nil, 2, 2) + server := httpserver(cs.getCert, nil, nil, 2, 2, nil) defer shutdownServer(server, t) hp := *listenAddr if strings.HasPrefix(hp, ":") { hp = fmt.Sprintf("localhost%s", hp) } - time.Sleep(1 * time.Second) // TODO(mkm) find a better way, e.g. retries + // Wait for the server to accept connections instead of sleeping a fixed + // amount of time and hoping it is ready. + waitForServer(t, hp) check := func(cert *x509.Certificate) { resp, err := http.Get(fmt.Sprintf("http://%s/v1/cert.pem", hp)) @@ -94,3 +119,55 @@ cs.setCert(certAfter) check(certAfter) } + +func TestHttpReadyz(t *testing.T) { + ready := false + server := httpserver(func() ([]*x509.Certificate, error) { + return nil, fmt.Errorf("no cert") + }, nil, nil, 2, 2, func() bool { return ready }) + defer shutdownServer(server, t) + + hp := *listenAddr + if strings.HasPrefix(hp, ":") { + hp = fmt.Sprintf("localhost%s", hp) + } + url := fmt.Sprintf("http://%s/readyz", hp) + healthURL := fmt.Sprintf("http://%s/healthz", hp) + + // Wait for listener + deadline := time.Now().Add(5 * time.Second) + for { + resp, err := http.Get(healthURL) + if err == nil { + resp.Body.Close() + if resp.StatusCode == http.StatusOK { + break + } + } + if time.Now().After(deadline) { + t.Fatal("server did not become reachable") + } + time.Sleep(50 * time.Millisecond) + } + + resp, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + body, _ := io.ReadAll(resp.Body) + resp.Body.Close() + if got, want := resp.StatusCode, http.StatusServiceUnavailable; got != want { + t.Fatalf("before ready: got status %v want %v body %q", got, want, body) + } + + ready = true + resp, err = http.Get(url) + if err != nil { + t.Fatal(err) + } + body, _ = io.ReadAll(resp.Body) + resp.Body.Close() + if got, want := resp.StatusCode, http.StatusOK; got != want { + t.Fatalf("after ready: got status %v want %v body %q", got, want, body) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubeseal-0.38.2/versions.env new/kubeseal-0.39.1/versions.env --- old/kubeseal-0.38.2/versions.env 2026-07-03 11:36:39.000000000 +0200 +++ new/kubeseal-0.39.1/versions.env 2026-08-20 10:43:03.000000000 +0200 @@ -1,2 +1,2 @@ -GO_VERSION=1.26.4 +GO_VERSION=1.26.7 GO_VERSION_LIST="[\"$GO_VERSION\"]" ++++++ kubeseal.obsinfo ++++++ --- /var/tmp/diff_new_pack.FnU8Mu/_old 2026-08-28 19:52:37.632976193 +0200 +++ /var/tmp/diff_new_pack.FnU8Mu/_new 2026-08-28 19:52:37.651976857 +0200 @@ -1,5 +1,5 @@ name: kubeseal -version: 0.38.2 -mtime: 1783071399 -commit: e88bf0ace0b5249d08623ea5cd203943549de7f3 +version: 0.39.1 +mtime: 1787215383 +commit: af17f829e4647765d5c576837261bf44863c96cc ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/kubeseal/vendor.tar.gz /work/SRC/openSUSE:Factory/.kubeseal.new.1265/vendor.tar.gz differ: char 30, line 1
