Skip to content

TRT-2702: Revert "STOR-3004: Rebase external-snapshotter to v8.6.0"#220

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
redhat-chai-bot:06111240-bot-changes
Jun 11, 2026
Merged

TRT-2702: Revert "STOR-3004: Rebase external-snapshotter to v8.6.0"#220
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
redhat-chai-bot:06111240-bot-changes

Conversation

@redhat-chai-bot

@redhat-chai-bot redhat-chai-bot commented Jun 11, 2026

Copy link
Copy Markdown

This reverts merge commit cab9af9 (PR #219).

Why

The v8.6.0 rebase changed the snapshot-controller to require VolumeGroupSnapshot CRDs at startup when CSIVolumeGroupSnapshot=true. In HyperShift hosted clusters, CRDs are installed asynchronously in the guest cluster, creating a race condition that causes 6–7 crash-loop restarts of csi-snapshot-controller before the CRDs become available.

This broke the 5.0 CI payload 5.0.0-0.ci-2026-06-11-001513 (rejected — baseline 5.0.0-0.ci-2026-06-10-181513 was Accepted).

Failing Jobs (100% failure rate)

  • hypershift-e2e-aks — 2/2 failures
  • hypershift-e2e-aws — 2/2 failures

Notes

The original PR's presubmit CI had no HyperShift coverage, so the race condition was undetected before merge. The rebase should be re-landed with a fix that makes the VolumeGroupSnapshot CRD dependency non-blocking at startup (e.g., retry loop or optional initialization).

/cc @rvagner78

Summary by CodeRabbit

Release Notes

  • Breaking Changes

    • Removed support for VolumeGroupSnapshot v1 API; v1beta2 is now required.
  • Chores

    • Updated Go toolchain to 1.25.x and Kubernetes dependencies to v0.30.0–v0.35.0.
    • Updated container image versions for csi-provisioner, csi-snapshotter, and hostpathplugin.
    • Updated CRD configurations for VolumeGroupSnapshot resources with conversion webhook support.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 11, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 11, 2026

Copy link
Copy Markdown

@redhat-chai-bot: This pull request references STOR-3004 which is a valid jira issue.

Details

In response to this:

This reverts merge commit cab9af9 (PR #219).

Why

The v8.6.0 rebase changed the snapshot-controller to require VolumeGroupSnapshot CRDs at startup when CSIVolumeGroupSnapshot=true. In HyperShift hosted clusters, CRDs are installed asynchronously in the guest cluster, creating a race condition that causes 6–7 crash-loop restarts of csi-snapshot-controller before the CRDs become available.

This broke the 5.0 CI payload 5.0.0-0.ci-2026-06-11-001513 (rejected — baseline 5.0.0-0.ci-2026-06-10-181513 was Accepted).

Failing Jobs (100% failure rate)

  • hypershift-e2e-aks — 2/2 failures
  • hypershift-e2e-aws — 2/2 failures

Notes

The original PR's presubmit CI had no HyperShift coverage, so the race condition was undetected before merge. The rebase should be re-landed with a fix that makes the VolumeGroupSnapshot CRD dependency non-blocking at startup (e.g., retry loop or optional initialization).

/cc @rvagner78

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot requested a review from rvagner78 June 11, 2026 12:40
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@redhat-chai-bot, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 3 minutes and 33 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 501fae15-9f3c-472d-8a49-ee8663df8ce0

📥 Commits

Reviewing files that changed from the base of the PR and between 1c12147 and 56ba1dc.

⛔ Files ignored due to path filters (197)
  • client/apis/volumegroupsnapshot/v1/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • client/apis/volumegroupsnapshot/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • client/apis/volumegroupsnapshot/v1beta2/zz_generated.deepcopy.go is excluded by !**/zz_generated*
  • client/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/fsnotify/fsnotify/.cirrus.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/backend_fen.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/backend_inotify.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/backend_kqueue.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/backend_windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/fsnotify.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/darwin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/freebsd.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/unix.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/unix2.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fsnotify/fsnotify/internal/windows.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/cache.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/decode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/decode_map_utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/diagnose.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/encode.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/simplevalue.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/structfields.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/tag.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/fxamacker/cbor/v2/valid.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/.cliff.toml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/NOTICE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/errors.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/ifaces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonpointer/pointer.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/.cliff.toml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/NOTICE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/jsonreference/reference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/CONTRIBUTORS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/go.work is excluded by !**/*.work, !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/jsonname/go_name_provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/jsonname/ifaces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/jsonname/name_provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/jsonutils/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/go-openapi/swag/mangling/BENCHMARK.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/BUILD.bazel is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/fieldpaths.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/inlining.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/library.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/program.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/prompt.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/cel/templates/authoring.tmpl is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/checker/checker.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/checker/cost.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/checker/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/checker/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/ast/ast.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/ast/conversion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/decls/decls.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/env/BUILD.bazel is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/env/env.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/env/io.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/overloads/overloads.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/stdlib/standard.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/err.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/list.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/object.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/optional.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/pb/file.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/pb/pb.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/pb/type.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/common/types/ref/provider.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/BUILD.bazel is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/costs.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/formatting.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/formatting_v2.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/lists.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/native.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/regex.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/sets.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/ext/strings.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/interpreter/attributes.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/interpreter/interpretable.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/google/cel-go/parser/parser.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/reporter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/COPYRIGHT is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/callmeta.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/CHANGELOG.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_reporter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/metric_options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_reporter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/go-grpc-prometheus/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options/BUILD.bazel is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/handler.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1beta1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumegroupsnapshot/v1beta2/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/clientset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/fake/clientset_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/fake/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/fake/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/scheme/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/scheme/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/fake/fake_volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/fake/fake_volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/fake/fake_volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/generated_expansion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1/volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshot_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/generated_expansion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshot_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshot_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/generated_expansion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshot_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/factory.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/generic.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/interface.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1/interface.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1/volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1/volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1/volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1beta1/interface.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1beta1/volumegroupsnapshot.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1beta1/volumegroupsnapshotclass.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/kubernetes-csi/external-snapshotter/client/v8/informers/externalversions/volumegroupsnapshot/v1beta1/volumegroupsnapshotcontent.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (103)
  • CHANGELOG/CHANGELOG-8.6.md
  • client/apis/volumegroupsnapshot/v1/register.go
  • client/apis/volumegroupsnapshot/v1/types.go
  • client/clientset/versioned/clientset.go
  • client/clientset/versioned/fake/clientset_generated.go
  • client/clientset/versioned/fake/doc.go
  • client/clientset/versioned/fake/register.go
  • client/clientset/versioned/scheme/doc.go
  • client/clientset/versioned/scheme/register.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1/fake/fake_volumegroupsnapshot.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1/fake/fake_volumegroupsnapshotclass.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1/fake/fake_volumegroupsnapshotcontent.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1/volumegroupsnapshot.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1/volumegroupsnapshotclass.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1/volumegroupsnapshotcontent.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/doc.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/doc.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshot.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshot_client.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshotclass.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/fake/fake_volumegroupsnapshotcontent.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/generated_expansion.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshot.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshot_client.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshotclass.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/volumegroupsnapshotcontent.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/doc.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/doc.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshot.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshot_client.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshotclass.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/fake/fake_volumegroupsnapshotcontent.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/generated_expansion.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshot_client.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshotclass.go
  • client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/volumegroupsnapshotcontent.go
  • client/config/crd/groupsnapshot.storage.k8s.io_volumegroupsnapshotclasses.yaml
  • client/config/crd/groupsnapshot.storage.k8s.io_volumegroupsnapshotcontents.yaml
  • client/config/crd/groupsnapshot.storage.k8s.io_volumegroupsnapshots.yaml
  • client/go.mod
  • client/hack/boilerplate.go.txt
  • client/informers/externalversions/factory.go
  • client/informers/externalversions/generic.go
  • client/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client/informers/externalversions/volumegroupsnapshot/interface.go
  • client/informers/externalversions/volumegroupsnapshot/v1/interface.go
  • client/informers/externalversions/volumegroupsnapshot/v1/volumegroupsnapshot.go
  • client/informers/externalversions/volumegroupsnapshot/v1/volumegroupsnapshotclass.go
  • client/informers/externalversions/volumegroupsnapshot/v1/volumegroupsnapshotcontent.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta1/interface.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta1/volumegroupsnapshot.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta1/volumegroupsnapshotclass.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta1/volumegroupsnapshotcontent.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta2/interface.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshotclass.go
  • client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshotcontent.go
  • client/listers/volumegroupsnapshot/v1/expansion_generated.go
  • client/listers/volumegroupsnapshot/v1/volumegroupsnapshot.go
  • client/listers/volumegroupsnapshot/v1/volumegroupsnapshotclass.go
  • client/listers/volumegroupsnapshot/v1/volumegroupsnapshotcontent.go
  • client/listers/volumegroupsnapshot/v1beta1/expansion_generated.go
  • client/listers/volumegroupsnapshot/v1beta1/volumegroupsnapshot.go
  • client/listers/volumegroupsnapshot/v1beta1/volumegroupsnapshotclass.go
  • client/listers/volumegroupsnapshot/v1beta1/volumegroupsnapshotcontent.go
  • client/listers/volumegroupsnapshot/v1beta2/expansion_generated.go
  • client/listers/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go
  • client/listers/volumegroupsnapshot/v1beta2/volumegroupsnapshotclass.go
  • client/listers/volumegroupsnapshot/v1beta2/volumegroupsnapshotcontent.go
  • cmd/csi-snapshotter/main.go
  • cmd/snapshot-controller/main.go
  • deploy/kubernetes/csi-snapshotter/setup-csi-snapshotter.yaml
  • deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
  • go.mod
  • pkg/common-controller/framework_test.go
  • pkg/common-controller/groupsnapshot_controller_helper.go
  • pkg/common-controller/groupsnapshot_create_test.go
  • pkg/common-controller/groupsnapshot_helper_test.go
  • pkg/common-controller/groupsnapshot_sync_test.go
  • pkg/common-controller/snapshot_controller.go
  • pkg/common-controller/snapshot_controller_base.go
  • pkg/common-controller/snapshot_delete_test.go
  • pkg/group_snapshotter/group_snapshotter_test.go
  • pkg/metrics/metrics.go
  • pkg/metrics/metrics_test.go
  • pkg/sidecar-controller/csi_handler.go
  • pkg/sidecar-controller/csi_handler_test.go
  • pkg/sidecar-controller/framework_test.go
  • pkg/sidecar-controller/groupsnapshot_controller_test.go
  • pkg/sidecar-controller/groupsnapshot_helper.go
  • pkg/sidecar-controller/groupsnapshot_helper_test.go
  • pkg/sidecar-controller/snapshot_controller_base.go
  • pkg/utils/patch.go
  • pkg/utils/util.go
  • pkg/utils/vgs.go
  • pkg/utils/vgs_test.go
  • pkg/webhook/webhook.go
  • release-tools/.github/workflows/codespell.yml
  • release-tools/.github/workflows/trivy.yaml
  • release-tools/cloudbuild.yaml
  • release-tools/prow.sh
  • release-tools/verify-vendor.sh

Walkthrough

The PR removes the v1 VolumeGroupSnapshot API surface, regenerates v1beta1/v1beta2 clients and informer/lister code, updates controller and utility code to use v1beta2 types and clients, and refreshes related CRDs, tests, manifests, and build tooling.

Changes

Group snapshot API migration

Layer / File(s) Summary
v1 API pruning
client/apis/volumegroupsnapshot/v1/*, client/clientset/versioned/*, client/listers/volumegroupsnapshot/v1/*, client/informers/externalversions/volumegroupsnapshot/v1/*
The v1 group snapshot API registration, public types, clientset entrypoint, and typed informer/lister implementations are removed.
v1beta1 and v1beta2 generated clients
client/clientset/versioned/typed/volumegroupsnapshot/v1beta1/*, client/clientset/versioned/typed/volumegroupsnapshot/v1beta2/*, client/clientset/versioned/fake/*, client/clientset/versioned/scheme/*, client/informers/externalversions/volumegroupsnapshot/v1beta1/*, client/informers/externalversions/volumegroupsnapshot/v1beta2/*, client/listers/volumegroupsnapshot/v1beta1/*, client/listers/volumegroupsnapshot/v1beta2/*
The v1beta1/v1beta2 generated typed clients, fakes, informer factories, and listers are rewritten around direct REST and cache/indexer operations with updated aliases and scheme wiring.
Controller and helper migration
pkg/common-controller/*, pkg/sidecar-controller/*, pkg/utils/*
The common controller, sidecar controller, utility helpers, and webhook/server wiring switch from v1 to v1beta2 group snapshot types and client calls.
Tests and CRDs
pkg/common-controller/*_test.go, pkg/sidecar-controller/*_test.go, pkg/utils/*_test.go, client/config/crd/*
Group snapshot tests and CRD manifests are updated for v1beta2 types, webhook conversion, and removed v1 coverage.
Tooling and release assets
go.mod, client/go.mod, deploy/kubernetes/*, release-tools/*, CHANGELOG/CHANGELOG-8.6.md, client/hack/boilerplate.go.txt
Module/toolchain metadata, deployment images, release workflows/scripts, and generated header/changelog files are refreshed.

Sequence Diagram(s)

sequenceDiagram
  participant Controller
  participant VersionedClientset
  participant RESTClient
  participant APIserver
  Controller->>VersionedClientset: GroupsnapshotV1beta2()
  VersionedClientset->>RESTClient: build typed request
  RESTClient->>APIserver: Get/List/Watch/Create/Update/Delete/Patch
  APIserver-->>RESTClient: typed response
  RESTClient-->>Controller: VolumeGroupSnapshot* objects
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

Suggested labels

approved, lgtm, verified

Suggested reviewers

  • jsafrane
  • dfajmon
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@openshift-ci openshift-ci Bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Jun 11, 2026
@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

Hi @redhat-chai-bot. Thanks for your PR.

I'm waiting for a openshift member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Tip

We noticed you've done this a few times! Consider joining the org to skip this step and gain /lgtm and other bot rights. We recommend asking approvers on your previous PRs to sponsor you.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
pkg/utils/vgs.go (1)

39-47: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve owner-reference compatibility for existing v1 objects.

Line 46 now accepts only groupsnapshot.storage.k8s.io/v1beta2. Existing snapshots with VolumeGroupSnapshot owner refs stamped as .../v1 will no longer be recognized as members, which can break upgrade behavior.

Suggested fix
 func getVolumeGroupSnapshotParentObjectName(snapshot *crdv1.VolumeSnapshot) string {
@@
-	apiVersion := fmt.Sprintf(
-		"%s/%s",
-		crdv1beta2.SchemeGroupVersion.Group,
-		crdv1beta2.SchemeGroupVersion.Version,
-	)
+	v1beta2APIVersion := fmt.Sprintf("%s/%s", crdv1beta2.SchemeGroupVersion.Group, crdv1beta2.SchemeGroupVersion.Version)
+	v1APIVersion := fmt.Sprintf("%s/%s", crdv1beta2.SchemeGroupVersion.Group, "v1")
@@
-		if owner.Kind == "VolumeGroupSnapshot" && owner.APIVersion == apiVersion {
+		if owner.Kind == "VolumeGroupSnapshot" &&
+			(owner.APIVersion == v1beta2APIVersion || owner.APIVersion == v1APIVersion) {
 			return owner.Name
 		}
 	}

Based on learnings: “Changes must be backward compatible; old code should still compile and runtime behavior cannot change in breaking ways.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/utils/vgs.go` around lines 39 - 47, The owner-ref check currently only
matches crdv1beta2.SchemeGroupVersion (groupsnapshot.storage.k8s.io/v1beta2)
which breaks recognition of older owner refs stamped as .../v1; update the logic
that iterates snapshot.ObjectMeta.OwnerReferences to also accept the same group
with version "v1" (e.g. build a second apiVersionV1 string from
crdv1beta2.SchemeGroupVersion.Group and "v1") and change the conditional that
tests owner.APIVersion to accept either apiVersion or apiVersionV1 when
owner.Kind == "VolumeGroupSnapshot", returning owner.Name in either case.

Source: Learnings

pkg/sidecar-controller/groupsnapshot_helper.go (1)

542-542: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Store the patched object in the group-snapshot cache, not contentStore.

After patching the annotation, this writes the VolumeGroupSnapshotContent through ctrl.storeContentUpdate(...). That updates the volume-snapshot-content cache with the wrong object type and leaves groupSnapshotContentStore stale until an informer round-trip.

Suggested fix
-	_, err = ctrl.storeContentUpdate(groupSnapshotContent)
+	_, err = ctrl.storeGroupSnapshotContentUpdate(groupSnapshotContent)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/sidecar-controller/groupsnapshot_helper.go` at line 542, The code is
calling ctrl.storeContentUpdate(...) with a VolumeGroupSnapshotContent
(groupSnapshotContent), which writes to the generic contentStore and leaves
groupSnapshotContentStore stale; replace that call so the patched object is
stored in the group-snapshot cache (use the controller helper that updates
groupSnapshotContentStore or directly update groupSnapshotContentStore with
groupSnapshotContent) instead of calling ctrl.storeContentUpdate; update the
call site that currently references ctrl.storeContentUpdate to call the
group-snapshot-specific store update (or the existing method that targets
groupSnapshotContentStore) so groupSnapshotContent is cached correctly.
release-tools/prow.sh (1)

843-856: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Injection risk: sed substitution uses unescaped variable.

The sed command on line 856 uses $image directly without escaping, which could fail or produce unexpected results if the image name contains sed metacharacters (e.g., /, &, \). While the risk is lower since $image is parsed from YAML with a controlled structure, defensive escaping should still be applied.

🛡️ Recommended fix: escape the image variable
                  image=$(echo "$nocomments" | sed -e 's;.*image:[[:space:]]*;;')
                  name=$(echo "$image" | sed -e 's;.*/\([^:]*\).*;\1;')
                  tag=$(echo "$image" | sed -e 's;.*:;;')

                  # Now replace registry and/or tag
                  NEW_TAG="csiprow"
-                  line="$(echo "$nocomments" | sed -e "s;$image;${name}:${NEW_TAG};")"
+                  escaped_image=$(printf '%s\n' "$image" | sed 's/[[\.*^$/]/\\&/g')
+                  line="$(echo "$nocomments" | sed -e "s;$escaped_image;${name}:${NEW_TAG};")"

As per coding guidelines: "Injection prevention: Validate at trust boundaries with allow-lists, not deny-lists" and "Command: no shell=True, os.system, or backtick exec with user input".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@release-tools/prow.sh` around lines 843 - 856, The sed substitution uses the
raw variable image (in the block handling nocomments -> image -> name -> tag and
building line with NEW_TAG), which can break or allow injection if image
contains sed metacharacters; before using image in the sed command that builds
line (the sed -e "s;$image;${name}:${NEW_TAG};"), compute an escaped version
(e.g., escape / and & and backslashes or choose a safe delimiter) and use that
escaped variable in the sed expression instead of $image so the substitution is
robust and safe.

Source: Coding guidelines

client/clientset/versioned/clientset.go (1)

33-38: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Public clientset contract break: removed GroupsnapshotV1() accessor.

Removing this exported method from Interface/Clientset is a compile-time break for existing consumers using the v1 entrypoint (Line 35-37, Line 49-56), which violates backward-compat expectations for this repo line.

Based on learnings: "Changes must be backward compatible; old code should still compile and runtime behavior cannot change in breaking ways."

Also applies to: 49-56

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/clientset/versioned/clientset.go` around lines 33 - 38, The public
Interface removed the backward-compatible accessor GroupsnapshotV1(); restore
the GroupsnapshotV1() method on the Interface and implement a corresponding
receiver method on Clientset that returns the same concrete subclient as the
existing GroupsnapshotV1beta1/GroupsnapshotV1beta2 accessors to preserve runtime
behavior. Specifically, add GroupsnapshotV1() to the Interface and implement
func (c *Clientset) GroupsnapshotV1() groupsnapshotv1.GroupsnapshotV1Interface {
return c.GroupsnapshotV1beta1() } (or delegate to the beta2 accessor if that
matches previous behavior) so existing callers compile without changing other
constructors or fields such as the Clientset subclient fields used by
GroupsnapshotV1beta1/GroupsnapshotV1beta2/SnapshotV1.

Source: Learnings

client/clientset/versioned/scheme/register.go (1)

35-39: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Keep v1 scheme registration for compatibility in v8.

Line 35-Line 39 no longer register groupsnapshotv1.AddToScheme. This drops decode/encode support for groupsnapshot.storage.k8s.io/v1 objects in composed schemes and can break existing consumers still handling persisted/legacy v1 objects. Keep v1 registration as compatibility plumbing until a planned major-version break.

Based on learnings, “Changes must be backward compatible; old code should still compile and runtime behavior cannot change in breaking ways”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/clientset/versioned/scheme/register.go` around lines 35 - 39, The
removal of groupsnapshotv1.AddToScheme from the runtime.SchemeBuilder
(localSchemeBuilder) drops support for groupsnapshot.storage.k8s.io/v1 objects;
restore backward compatibility by re-adding groupsnapshotv1.AddToScheme to the
localSchemeBuilder list so that the composed scheme still registers the v1 API,
ensuring functions that rely on AddToScheme (localSchemeBuilder) continue to
decode/encode legacy v1 objects until the planned major-version break.

Source: Learnings

pkg/common-controller/framework_test.go (2)

301-361: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Group snapshot content paths are reading the wrong backing map.

In the volumegroupsnapshotcontents create/update branches, existence/version checks read r.contents (volume snapshot content map) instead of r.groupContents. That can produce incorrect “already exists/not found/version conflict” behavior for group-content tests.

Suggested fix
- _, found := r.contents[content.Name]
+ _, found := r.groupContents[content.Name]
...
- storedVolume, found := r.contents[content.Name]
+ storedGroupContent, found := r.groupContents[content.Name]
  if found {
-   storedVer, _ := strconv.Atoi(storedVolume.ResourceVersion)
+   storedVer, _ := strconv.Atoi(storedGroupContent.ResourceVersion)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/common-controller/framework_test.go` around lines 301 - 361, The
volumegroupsnapshotcontents branches are incorrectly reading/writing the volume
snapshot map (r.contents) instead of the group snapshot map (r.groupContents);
in the action.Matches("create", "volumegroupsnapshotcontents") and
action.Matches("update", "volumegroupsnapshotcontents") cases, replace lookups
like r.contents[content.Name] and assignments r.contents[content.Name] with
r.groupContents[content.Name] (and ensure storedVolume typed to the
group-content element), so existence checks, version bumps (using
storedVer/requestedVer and errVersionConflict) and final storage use
r.groupContents consistently while keeping the rest of the logic (DeepCopy,
ResourceVersion increment, changedObjects appends) unchanged.

284-304: ⚠️ Potential issue | 🟠 Major

Fix snapshotReactor create action casts and group-content map lookups

  • create reactors for both volumesnapshotcontents and volumegroupsnapshotcontents cast the "create" action to core.UpdateAction, which can panic; use core.CreateAction instead.
  • volumegroupsnapshotcontents create/update existence/version checks read from r.contents but results are stored in r.groupContents; use r.groupContents for the lookups.
Suggested fix
- obj := action.(core.UpdateAction).GetObject()
+ obj := action.(core.CreateAction).GetObject()
...
- obj := action.(core.UpdateAction).GetObject()
+ obj := action.(core.CreateAction).GetObject()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/common-controller/framework_test.go` around lines 284 - 304, The create
reactors for "volumesnapshotcontents" and "volumegroupsnapshotcontents" are
incorrectly casting the action to core.UpdateAction and the group-content branch
is checking r.contents instead of r.groupContents; change the cast to
core.CreateAction when handling the create action (where you call action.(...)
to get the object) and in the "volumegroupsnapshotcontents" create/update
existence/version checks switch lookups from r.contents to r.groupContents so
you read and store against the correct map (refer to the action.Matches cases,
the core.CreateAction cast, r.contents, r.groupContents, and the types
crdv1.VolumeSnapshotContent / crdv1beta2.VolumeGroupSnapshotContent).
pkg/common-controller/snapshot_controller.go (1)

1012-1023: ⚠️ Potential issue | 🟠 Major

Fix conflict retry in removePVCFinalizer by preserving the original update error

removePVCFinalizer returns newControllerUpdateError(newPvc.Name, err.Error()) from inside retry.RetryOnConflict. newControllerUpdateError creates a controllerUpdateError that only stores a message string (no Unwrap / no underlying error), so k8s.io/apimachinery/pkg/api/errors.IsConflict can’t detect the original apierrors.StatusError via errors.As. As a result, RetryOnConflict won’t retry on conflicts.

Suggested fix
-func (ctrl *csiSnapshotCommonController) removePVCFinalizer(pvc *v1.PersistentVolumeClaim) error {
-	return retry.RetryOnConflict(retry.DefaultRetry, func() error {
+func (ctrl *csiSnapshotCommonController) removePVCFinalizer(pvc *v1.PersistentVolumeClaim) error {
+	err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
 		// Get snapshot source which is a PVC
 		newPvc, err := ctrl.client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvc.Name, metav1.GetOptions{})
 		if err != nil {
 			return err
 		}
 		newPvc = newPvc.DeepCopy()
 		newPvc.ObjectMeta.Finalizers = utils.RemoveString(newPvc.ObjectMeta.Finalizers, utils.PVCFinalizer)
 		_, err = ctrl.client.CoreV1().PersistentVolumeClaims(newPvc.Namespace).Update(context.TODO(), newPvc, metav1.UpdateOptions{})
 		if err != nil {
-			return newControllerUpdateError(newPvc.Name, err.Error())
+			return err
 		}
 
 		klog.V(5).Infof("Removed protection finalizer from persistent volume claim %s", pvc.Name)
 		return nil
 	})
+	if err != nil {
+		return newControllerUpdateError(pvc.Name, err.Error())
+	}
+	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/common-controller/snapshot_controller.go` around lines 1012 - 1023, The
retry closure in removePVCFinalizer currently returns
newControllerUpdateError(newPvc.Name, err.Error()) which discards the original
error type and prevents errors.IsConflict/RetryOnConflict from detecting
apierrors.StatusError; fix by preserving/wrapping the original error instead
(either change newControllerUpdateError to wrap the original err using %w or
replace the return with a wrapped error like fmt.Errorf("update pvc %s: %w",
newPvc.Name, err)) so the underlying apierrors.StatusError is retained for
errors.As/IsConflict to work correctly.
🧹 Nitpick comments (1)
deploy/kubernetes/csi-snapshotter/setup-csi-snapshotter.yaml (1)

74-121: 💤 Low value

Consider adding resource limits and security context for production use.

While this appears to be a test/demo manifest (based on comments), consider documenting that production deployments should add:

  • resources.limits and resources.requests for CPU and memory on all containers
  • securityContext with runAsNonRoot, readOnlyRootFilesystem, and allowPrivilegeEscalation: false where appropriate (noting that the hostpath container legitimately requires privileged: true for storage operations)

This recommendation aligns with Kubernetes security best practices, though it's acceptable to defer for test manifests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/kubernetes/csi-snapshotter/setup-csi-snapshotter.yaml` around lines 74
- 121, Add guidance and defaults for production: update the containers
csi-provisioner and csi-snapshotter (and any other non-privileged containers) to
include resources.requests and resources.limits for CPU and memory, and add a
securityContext with runAsNonRoot: true, readOnlyRootFilesystem: true, and
allowPrivilegeEscalation: false; keep the hostpath container's existing
securityContext privileged: true and document that it requires privileged mode,
and call out the socket-dir volume usage so reviewers know where these settings
apply.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@client/config/crd/groupsnapshot.storage.k8s.io_volumegroupsnapshotcontents.yaml`:
- Around line 20-28: The CRD currently hard-codes the conversion webhook service
namespace (clientConfig.service.namespace: default) pointing to
snapshot-conversion-webhook-service which breaks installs that run the webhook
in another namespace; change the CRD to not hard-code "default" but instead
reference a templated/configurable namespace for the conversion webhook (or
remove the fixed namespace and populate it at install time) so the
conversion.clientConfig.service.namespace is provided from the chart/installer
(e.g., via a Helm value or template variable) and keep the service name
snapshot-conversion-webhook-service and path /convert as-is to maintain
compatibility.

In `@client/informers/externalversions/factory.go`:
- Around line 208-209: The example incorrectly assigns ctx, cancel from
context.Background(); change the example to call context.WithCancel to obtain
both values so defer cancel() is valid—replace the use of context.Background()
with context.WithCancel(context.Background()) so ctx and cancel are correctly
declared (symbols to update: ctx, cancel, context.Background(),
context.WithCancel(), and the existing defer cancel()).

In
`@client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go`:
- Around line 58-72: The informer uses context.TODO() in
NewFilteredVolumeGroupSnapshotInformer's cache.ListWatch ListFunc/WatchFunc
which prevents cancellation on shutdown; change the ListFunc/WatchFunc to
ListWithContextFunc and WatchFuncWithContext and forward the provided ctx into
the typed client calls (call
client.GroupsnapshotV1beta2().VolumeGroupSnapshots(namespace).List(ctx, options)
and .Watch(ctx, options)), preserving the tweakListOptions(&options) behavior
before invoking the client so in-flight list/watch requests are cancellable by
the informer context.

In `@cmd/snapshot-controller/main.go`:
- Around line 118-134: The current startup treats missing VolumeGroupSnapshot
CRDs as a fatal preflight (in the enableVolumeGroupSnapshots check calling
client.GroupsnapshotV1beta2().VolumeGroupSnapshots().List /
VolumeGroupSnapshotClasses().List / VolumeGroupSnapshotContents().List) and
returns/exit on error; change this to non-fatal behavior by logging a warning
(klog.Warningf) when any of those List calls fail, not returning false or
exiting, and defer activation: either disable volume-group-snapshot features
until CRDs are detected or spawn a background goroutine that retries those List
calls with backoff and enables the feature once successful; also remove/replace
any direct process exit at the exit path referenced (the code around the earlier
timeout exit) so the controller continues running and can recover when CRDs are
installed.

In `@deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml`:
- Line 37: Verify the snapshot-controller image tag
registry.k8s.io/sig-storage/snapshot-controller:v8.4.0 exists upstream and
document CVE/patch differences vs v8.5.0 (ensure the
HyperShift/VolumeGroupSnapshot v1beta2 fix remains); then harden the pod spec
that runs the snapshot controller by adding container-level resources, a
securityContext (runAsNonRoot: true, readOnlyRootFilesystem: true,
dropCapabilities: [ALL], allowPrivilegeEscalation: false), livenessProbe and
readinessProbe entries, and set automountServiceAccountToken: false on the
Pod/Deployment spec; preserve minReadySeconds: 35 as noted. Include these
changes around the container declaration that references the image line so
reviewers can find the updated pod/deployment spec.

In `@go.mod`:
- Around line 86-92: Bump the vulnerable OpenTelemetry module versions in
go.mod: update go.opentelemetry.io/otel and go.opentelemetry.io/otel/sdk to
their patched releases (replace v1.40.0 with the fixed versions), then
re-resolve the module graph by running go mod tidy (and commit the updated
go.sum); ensure any related indirect modules (e.g., otlptrace, otlptracegrpc,
metric, trace) are compatible and updated if needed so the build and tests pass.

In `@pkg/common-controller/snapshot_controller.go`:
- Around line 285-292: The code in
checkandRemoveSnapshotFinalizersAndCheckandDeleteContent returns nil when
isVolumeBeingCreatedFromSnapshot(snapshot) is true, which prevents immediate
requeue and can leave the Snapshot stuck; change this to trigger a requeue
instead of treating it as handled — e.g., return a requeue signal/error so the
controller retries later (for example, return a small requeue error like
fmt.Errorf("snapshot in use for PVC restore, requeue") or use the controller's
existing requeue helper if one exists), keeping the check using
isVolumeBeingCreatedFromSnapshot and preserving the eventRecorder log.

In `@pkg/metrics/metrics.go`:
- Around line 299-311: The goroutine in
operationMetricsManager.scheduleOpsInFlightMetric creates a new time.Ticker in a
for-range and never stops it, and ctx.Done() is only checked outside that inner
loop; fix by creating a ticker once (ticker :=
time.NewTicker(inFlightCheckInterval)) and using a single select loop like: for
{ select { case <-ctx.Done(): ticker.Stop(); return; case <-ticker.C:
opMgr.mu.Lock(); opMgr.opInFlight.Set(float64(len(opMgr.cache)));
opMgr.mu.Unlock() } } so the ticker is stopped on cancellation and the goroutine
exits promptly.

In `@pkg/utils/util.go`:
- Around line 405-406: The exported helper GetGroupSnapshotSecretReference was
changed to accept v1beta2 types, which breaks downstream callers; revert the
public signature to accept the original v1 types and restore its original
behavior, and add a new v1beta2-specific entry point (e.g.,
GetGroupSnapshotSecretReferenceV1Beta2 or a wrapper function) that converts
v1beta2 inputs to v1 or delegates to shared internal logic; apply the same
pattern for the other exported helpers you modified (the additional helpers
flagged in the comment) by keeping their original v1 signatures and adding
separate v1beta2 wrappers/shims that perform any necessary type conversion or
call into common unexported functions.

In `@pkg/webhook/webhook.go`:
- Around line 45-48: The http.Server instance assigned to srv omits
ReadTimeout/WriteTimeout/IdleTimeout, exposing the server to connection-hold
DoS; update the http.Server initialization (where srv is constructed) to set
sensible ReadTimeout, WriteTimeout, and IdleTimeout values (e.g.,
seconds/minutes appropriate for your handlers) and ensure any long-running
operations respect context cancellation (use the request context.Context in
handler functions) so that connections/timeouts are enforced and resources are
not held indefinitely.

In `@release-tools/.github/workflows/codespell.yml`:
- Around line 11-12: The workflow uses floating action references
(actions/checkout@v6 and codespell-project/actions-codespell@master); replace
these with full commit SHAs to pin dependencies and update any other workflows
(e.g., trivy.yaml) that also use unpinned refs. Locate the two uses in the
workflow (the lines referencing actions/checkout and
codespell-project/actions-codespell) and change them to their corresponding full
commit SHA references (e.g., actions/checkout@<commit-sha> and
codespell-project/actions-codespell@<commit-sha>), ensuring you fetch the exact
commit SHAs from the actions' repositories and use those pinned SHAs
consistently across all workflows.

---

Outside diff comments:
In `@client/clientset/versioned/clientset.go`:
- Around line 33-38: The public Interface removed the backward-compatible
accessor GroupsnapshotV1(); restore the GroupsnapshotV1() method on the
Interface and implement a corresponding receiver method on Clientset that
returns the same concrete subclient as the existing
GroupsnapshotV1beta1/GroupsnapshotV1beta2 accessors to preserve runtime
behavior. Specifically, add GroupsnapshotV1() to the Interface and implement
func (c *Clientset) GroupsnapshotV1() groupsnapshotv1.GroupsnapshotV1Interface {
return c.GroupsnapshotV1beta1() } (or delegate to the beta2 accessor if that
matches previous behavior) so existing callers compile without changing other
constructors or fields such as the Clientset subclient fields used by
GroupsnapshotV1beta1/GroupsnapshotV1beta2/SnapshotV1.

In `@client/clientset/versioned/scheme/register.go`:
- Around line 35-39: The removal of groupsnapshotv1.AddToScheme from the
runtime.SchemeBuilder (localSchemeBuilder) drops support for
groupsnapshot.storage.k8s.io/v1 objects; restore backward compatibility by
re-adding groupsnapshotv1.AddToScheme to the localSchemeBuilder list so that the
composed scheme still registers the v1 API, ensuring functions that rely on
AddToScheme (localSchemeBuilder) continue to decode/encode legacy v1 objects
until the planned major-version break.

In `@pkg/common-controller/framework_test.go`:
- Around line 301-361: The volumegroupsnapshotcontents branches are incorrectly
reading/writing the volume snapshot map (r.contents) instead of the group
snapshot map (r.groupContents); in the action.Matches("create",
"volumegroupsnapshotcontents") and action.Matches("update",
"volumegroupsnapshotcontents") cases, replace lookups like
r.contents[content.Name] and assignments r.contents[content.Name] with
r.groupContents[content.Name] (and ensure storedVolume typed to the
group-content element), so existence checks, version bumps (using
storedVer/requestedVer and errVersionConflict) and final storage use
r.groupContents consistently while keeping the rest of the logic (DeepCopy,
ResourceVersion increment, changedObjects appends) unchanged.
- Around line 284-304: The create reactors for "volumesnapshotcontents" and
"volumegroupsnapshotcontents" are incorrectly casting the action to
core.UpdateAction and the group-content branch is checking r.contents instead of
r.groupContents; change the cast to core.CreateAction when handling the create
action (where you call action.(...) to get the object) and in the
"volumegroupsnapshotcontents" create/update existence/version checks switch
lookups from r.contents to r.groupContents so you read and store against the
correct map (refer to the action.Matches cases, the core.CreateAction cast,
r.contents, r.groupContents, and the types crdv1.VolumeSnapshotContent /
crdv1beta2.VolumeGroupSnapshotContent).

In `@pkg/common-controller/snapshot_controller.go`:
- Around line 1012-1023: The retry closure in removePVCFinalizer currently
returns newControllerUpdateError(newPvc.Name, err.Error()) which discards the
original error type and prevents errors.IsConflict/RetryOnConflict from
detecting apierrors.StatusError; fix by preserving/wrapping the original error
instead (either change newControllerUpdateError to wrap the original err using
%w or replace the return with a wrapped error like fmt.Errorf("update pvc %s:
%w", newPvc.Name, err)) so the underlying apierrors.StatusError is retained for
errors.As/IsConflict to work correctly.

In `@pkg/sidecar-controller/groupsnapshot_helper.go`:
- Line 542: The code is calling ctrl.storeContentUpdate(...) with a
VolumeGroupSnapshotContent (groupSnapshotContent), which writes to the generic
contentStore and leaves groupSnapshotContentStore stale; replace that call so
the patched object is stored in the group-snapshot cache (use the controller
helper that updates groupSnapshotContentStore or directly update
groupSnapshotContentStore with groupSnapshotContent) instead of calling
ctrl.storeContentUpdate; update the call site that currently references
ctrl.storeContentUpdate to call the group-snapshot-specific store update (or the
existing method that targets groupSnapshotContentStore) so groupSnapshotContent
is cached correctly.

In `@pkg/utils/vgs.go`:
- Around line 39-47: The owner-ref check currently only matches
crdv1beta2.SchemeGroupVersion (groupsnapshot.storage.k8s.io/v1beta2) which
breaks recognition of older owner refs stamped as .../v1; update the logic that
iterates snapshot.ObjectMeta.OwnerReferences to also accept the same group with
version "v1" (e.g. build a second apiVersionV1 string from
crdv1beta2.SchemeGroupVersion.Group and "v1") and change the conditional that
tests owner.APIVersion to accept either apiVersion or apiVersionV1 when
owner.Kind == "VolumeGroupSnapshot", returning owner.Name in either case.

In `@release-tools/prow.sh`:
- Around line 843-856: The sed substitution uses the raw variable image (in the
block handling nocomments -> image -> name -> tag and building line with
NEW_TAG), which can break or allow injection if image contains sed
metacharacters; before using image in the sed command that builds line (the sed
-e "s;$image;${name}:${NEW_TAG};"), compute an escaped version (e.g., escape /
and & and backslashes or choose a safe delimiter) and use that escaped variable
in the sed expression instead of $image so the substitution is robust and safe.

---

Nitpick comments:
In `@deploy/kubernetes/csi-snapshotter/setup-csi-snapshotter.yaml`:
- Around line 74-121: Add guidance and defaults for production: update the
containers csi-provisioner and csi-snapshotter (and any other non-privileged
containers) to include resources.requests and resources.limits for CPU and
memory, and add a securityContext with runAsNonRoot: true,
readOnlyRootFilesystem: true, and allowPrivilegeEscalation: false; keep the
hostpath container's existing securityContext privileged: true and document that
it requires privileged mode, and call out the socket-dir volume usage so
reviewers know where these settings apply.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment on lines +20 to +28
conversion:
strategy: Webhook
webhook:
conversionReviewVersions: ["v1"]
clientConfig:
service:
namespace: default
name: snapshot-conversion-webhook-service
path: /convert

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don’t hard-code the conversion webhook into default.

This CRD is cluster-scoped, but the conversion endpoint is now pinned to snapshot-conversion-webhook-service.default. Any install that runs the webhook in another namespace will fail v1beta1↔v1beta2 conversions, which turns requests against the non-storage version into API errors. Please make this follow the actual deployment namespace or template it at install time. Based on learnings, changes must be backward compatible; hard-coding a namespace-specific conversion endpoint changes runtime requirements for existing installs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@client/config/crd/groupsnapshot.storage.k8s.io_volumegroupsnapshotcontents.yaml`
around lines 20 - 28, The CRD currently hard-codes the conversion webhook
service namespace (clientConfig.service.namespace: default) pointing to
snapshot-conversion-webhook-service which breaks installs that run the webhook
in another namespace; change the CRD to not hard-code "default" but instead
reference a templated/configurable namespace for the conversion webhook (or
remove the fixed namespace and populate it at install time) so the
conversion.clientConfig.service.namespace is provided from the chart/installer
(e.g., via a Helm value or template variable) and keep the service name
snapshot-conversion-webhook-service and path /convert as-is to maintain
compatibility.

Source: Learnings

Comment on lines +208 to 209
// ctx, cancel := context.Background()
// defer cancel()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix broken context example in documentation.

The example code has invalid Go syntax:

ctx, cancel := context.Background()
defer cancel()

context.Background() returns only one value (a Context), so this multiple assignment will fail. The code should be either:

  • ctx := context.Background() (no cancel), or
  • ctx, cancel := context.WithCancel(context.Background()) (with cancel)

Since defer cancel() appears on line 209, the intended pattern is likely the second option.

📝 Suggested fix
-	ctx, cancel := context.Background()
+	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/informers/externalversions/factory.go` around lines 208 - 209, The
example incorrectly assigns ctx, cancel from context.Background(); change the
example to call context.WithCancel to obtain both values so defer cancel() is
valid—replace the use of context.Background() with
context.WithCancel(context.Background()) so ctx and cancel are correctly
declared (symbols to update: ctx, cancel, context.Background(),
context.WithCancel(), and the existing defer cancel()).

Comment on lines 58 to 72
func NewFilteredVolumeGroupSnapshotInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GroupsnapshotV1beta2().VolumeGroupSnapshots(namespace).List(context.Background(), options)
return client.GroupsnapshotV1beta2().VolumeGroupSnapshots(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GroupsnapshotV1beta2().VolumeGroupSnapshots(namespace).Watch(context.Background(), options)
return client.GroupsnapshotV1beta2().VolumeGroupSnapshots(namespace).Watch(context.TODO(), options)
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Check this informer's list/watch context usage"
rg -n -C2 'context\.TODO\(\)|ListWithContextFunc|WatchFunc|ToListWatcherWithWatchListSemantics' client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go

echo
echo "2) Compare with other generated informers for context-aware patterns"
rg -n -C2 'ListWithContextFunc|ToListWatcherWithWatchListSemantics|context\.TODO\(\)' client/informers/externalversions --type go

echo
echo "3) Confirm client-go version(s) that generator behavior is tied to"
rg -n 'k8s\.io/client-go' go.mod client/go.mod || true

Repository: openshift/csi-external-snapshotter

Length of output: 11884


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repo vendor presence (if any):"
ls -la | sed -n '1,120p'
echo

echo "Search for context-aware ListWatch callback fields in the repo:"
rg -n --hidden "ListWithContextFunc|WatchWithContextFunc" . || true
echo

echo "If module cache is available, search for ListWatch definition in k8s.io/client-go:"
if command -v go >/dev/null 2>&1; then
  GOPATH="$(go env GOPATH 2>/dev/null || true)"
  if [ -n "${GOPATH}" ] && [ -d "$GOPATH/pkg/mod" ]; then
    rg -n "type ListWatch struct" "$GOPATH/pkg/mod" -S -g '*client-go*' | head -n 50
    echo
    rg -n "ListWithContextFunc|WatchWithContextFunc" "$GOPATH/pkg/mod" -S -g '*client-go*' | head -n 50
  else
    echo "No GOPATH/pkg/mod directory found in sandbox."
  fi
else
  echo "go command not found in sandbox."
fi

Repository: openshift/csi-external-snapshotter

Length of output: 27388


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspect ListWatch context semantics:"
sed -n '1,220p' vendor/k8s.io/client-go/tools/cache/listwatch.go | cat -n
echo
sed -n '220,360p' vendor/k8s.io/client-go/tools/cache/listwatch.go | cat -n

echo
echo "Search for NewSharedIndexInformer and Reflector run loop:"
rg -n "func NewSharedIndexInformer|type Reflector|func \\(.*\\) Run\\(|ListWatch\\." vendor/k8s.io/client-go/tools/cache -S

echo
echo "Inspect reflector where list/watch are invoked:"
rg -n "lw\\.List|lw\\.Watch|ListWithContextFunc|WatchWithContextFunc" vendor/k8s.io/client-go/tools/cache/reflector.go -n
echo
sed -n '1,260p' vendor/k8s.io/client-go/tools/cache/reflector.go | cat -n
echo
sed -n '260,520p' vendor/k8s.io/client-go/tools/cache/reflector.go | cat -n

Repository: openshift/csi-external-snapshotter

Length of output: 15054


🏁 Script executed:

#!/bin/bash
set -u

echo "Find where Reflector calls List/Watch (with context) in reflector.go"
rg -n "ListWithContext\\(|WatchWithContext\\(|List\\(|Watch\\(|ToListerWatcherWithContext|context\\.With" vendor/k8s.io/client-go/tools/cache/reflector.go

echo
echo "Show Reflector.Run and nearby code paths"
sed -n '320,520p' vendor/k8s.io/client-go/tools/cache/reflector.go | cat -n

echo
echo "Show Reflector.list / Reflector.watch (likely helper methods)"
rg -n "func \\(r \\*Reflector\\) (list|watch|List|Watch)" vendor/k8s.io/client-go/tools/cache/reflector.go || true
sed -n '520,820p' vendor/k8s.io/client-go/tools/cache/reflector.go | cat -n

echo
echo "Inspect shared informer wiring to Reflector (stopCh/context)"
sed -n '240,420p' vendor/k8s.io/client-go/tools/cache/shared_informer.go | cat -n

Repository: openshift/csi-external-snapshotter

Length of output: 34182


Replace context.TODO() with the reflector/informer context in List/Watch

client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go hardcodes context.TODO() in the cache.ListWatch ListFunc/WatchFunc calls (lines 65, 71). Reflector uses ListWithContext(ctx)/WatchWithContext(ctx), but because ListWithContextFunc/WatchFuncWithContext are unset, those calls fall back to ListFunc/WatchFunc, so shutdown cancellation won’t stop in-flight list/watch requests. Switch to ListWithContextFunc/WatchFuncWithContext and pass through the provided ctx to the typed client List/Watch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@client/informers/externalversions/volumegroupsnapshot/v1beta2/volumegroupsnapshot.go`
around lines 58 - 72, The informer uses context.TODO() in
NewFilteredVolumeGroupSnapshotInformer's cache.ListWatch ListFunc/WatchFunc
which prevents cancellation on shutdown; change the ListFunc/WatchFunc to
ListWithContextFunc and WatchFuncWithContext and forward the provided ctx into
the typed client calls (call
client.GroupsnapshotV1beta2().VolumeGroupSnapshots(namespace).List(ctx, options)
and .Watch(ctx, options)), preserving the tweakListOptions(&options) behavior
before invoking the client so in-flight list/watch requests are cancellable by
the informer context.

Source: Coding guidelines

Comment on lines 118 to 134
if enableVolumeGroupSnapshots {
_, err = client.GroupsnapshotV1().VolumeGroupSnapshots("").List(ctx, listOptions)
_, err = client.GroupsnapshotV1beta2().VolumeGroupSnapshots("").List(ctx, listOptions)
if err != nil {
klog.Errorf("Failed to list v1 volumegroupsnapshots with error=%+v", err)
klog.Errorf("Failed to list v1beta2 volumegroupsnapshots with error=%+v", err)
return false, nil
}

_, err = client.GroupsnapshotV1().VolumeGroupSnapshotClasses().List(ctx, listOptions)
_, err = client.GroupsnapshotV1beta2().VolumeGroupSnapshotClasses().List(ctx, listOptions)
if err != nil {
klog.Errorf("Failed to list v1 volumegroupsnapshotclasses with error=%+v", err)
klog.Errorf("Failed to list v1beta2 volumegroupsnapshotclasses with error=%+v", err)
return false, nil
}
_, err = client.GroupsnapshotV1().VolumeGroupSnapshotContents().List(ctx, listOptions)
_, err = client.GroupsnapshotV1beta2().VolumeGroupSnapshotContents().List(ctx, listOptions)
if err != nil {
klog.Errorf("Failed to list v1 volumegroupsnapshotcontents with error=%+v", err)
klog.Errorf("Failed to list v1beta2 volumegroupsnapshotcontents with error=%+v", err)
return false, nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Startup still hard-fails on missing VolumeGroupSnapshot CRDs.

Line 118-Line 134 make group-snapshot CRD presence a blocking preflight, and Line 258-Line 260 exit the process when it times out. In environments where CRDs are installed asynchronously, this preserves crash-loop startup behavior. Make group-snapshot CRD readiness non-fatal at startup (warn + background retry / delayed activation) so the controller can stay up and recover when CRDs appear.

Also applies to: 258-260

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/snapshot-controller/main.go` around lines 118 - 134, The current startup
treats missing VolumeGroupSnapshot CRDs as a fatal preflight (in the
enableVolumeGroupSnapshots check calling
client.GroupsnapshotV1beta2().VolumeGroupSnapshots().List /
VolumeGroupSnapshotClasses().List / VolumeGroupSnapshotContents().List) and
returns/exit on error; change this to non-fatal behavior by logging a warning
(klog.Warningf) when any of those List calls fail, not returning false or
exiting, and defer activation: either disable volume-group-snapshot features
until CRDs are detected or spawn a background goroutine that retries those List
calls with backoff and enables the feature once successful; also remove/replace
any direct process exit at the exit path referenced (the code around the earlier
timeout exit) so the controller continues running and can recover when CRDs are
installed.

containers:
- name: snapshot-controller
image: registry.k8s.io/sig-storage/snapshot-controller:v8.5.0
image: registry.k8s.io/sig-storage/snapshot-controller:v8.4.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify snapshot-controller v8.4.0 exists and check for security issues

echo "=== Checking snapshot-controller v8.4.0 image ==="
docker manifest inspect "registry.k8s.io/sig-storage/snapshot-controller:v8.4.0" >/dev/null 2>&1 && echo "✓ Image exists" || echo "✗ Image not found"

echo ""
echo "=== Checking external-snapshotter v8.4.0 release ==="
gh api repos/kubernetes-csi/external-snapshotter/releases/tags/v8.4.0 --jq '.name, .published_at, .body' 2>/dev/null | head -20

echo ""
echo "=== Checking v8.5.0 release notes for critical fixes ==="
gh api repos/kubernetes-csi/external-snapshotter/releases/tags/v8.5.0 --jq '.name, .body' 2>/dev/null | head -30

Repository: openshift/csi-external-snapshotter

Length of output: 1922


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Check registry.k8s.io manifest existence for the exact tag (no docker dependency)
echo "=== Checking registry.k8s.io manifest for snapshot-controller:v8.4.0 ==="
python3 - <<'PY'
import base64, json, os, sys, urllib.request

url = "https://registry.k8s.io/v2/sig-storage/snapshot-controller/manifests/v8.4.0"
req = urllib.request.Request(url, method="GET", headers={
  "Accept": "application/vnd.docker.distribution.manifest.v2+json"
})
try:
  with urllib.request.urlopen(req, timeout=20) as resp:
    print("✓ Exists (HTTP %s)" % resp.status)
except urllib.error.HTTPError as e:
  # 401/403 may indicate auth; still captures truthiness better than “not found”
  print("✗ Not accessible as anonymous (HTTP %s)" % e.code)
except Exception as e:
  print("✗ Error:", e)
PY

# 2) Fetch changelog content for v8.5.0 and v8.4.0 and search for security + VolumeGroupSnapshot v1beta2 references
echo ""
echo "=== Searching upstream CHANGELOG-8.5.md for CVE/security + VolumeGroupSnapshot v1beta2 ==="
python3 - <<'PY'
import re, sys, urllib.request
base = "https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter"
def fetch(ref, path):
  url = f"{base}/{ref}/{path}"
  with urllib.request.urlopen(url, timeout=20) as r:
    return r.read().decode("utf-8", "replace")
text_85 = fetch("v8.5.0", "CHANGELOG/CHANGELOG-8.5.md")
patterns = [
  r"CVE[-\s]?\d+",
  r"\bsecurity\b",
  r"\bvulnerability\b",
  r"VolumeGroupSnapshot",
  r"v1beta2"
]
for pat in patterns:
  hits = [(m.start(), m.group(0) if hasattr(m, "group") else "") for m in re.finditer(pat, text_85, flags=re.IGNORECASE)]
  if hits:
    print(f"== Matches for {pat} (showing up to 10 hits) ==")
    for m in re.finditer(pat, text_85, flags=re.IGNORECASE):
      # print containing line
      line_start = text_85.rfind("\n", 0, m.start())+1
      line_end = text_85.find("\n", m.end())
      line = text_85[line_start:line_end]
      print(line.strip())
      if "CVE" in pat.upper() and len(hits) >= 10: break
      # cap output globally
    print()
PY

echo ""
echo "=== Searching upstream CHANGELOG-8.4.md for VolumeGroupSnapshot v1beta2 references ==="
python3 - <<'PY'
import re, urllib.request
base = "https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter"
url = f"{base}/v8.4.0/CHANGELOG/CHANGELOG-8.4.md"
with urllib.request.urlopen(url, timeout=20) as r:
  text = r.read().decode("utf-8", "replace")
for pat in [r"VolumeGroupSnapshot", r"v1beta2", r"beta2"]:
  print(f"== Matches for {pat} ==")
  found=0
  for m in re.finditer(pat, text, flags=re.IGNORECASE):
    line_start = text.rfind("\n", 0, m.start())+1
    line_end = text.find("\n", m.end())
    line = text[line_start:line_end]
    if line.strip():
      print(line.strip())
      found += 1
      if found>=20: break
  if found==0: print("(none)")
  print()
PY

Repository: openshift/csi-external-snapshotter

Length of output: 3033


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Fetch changelog files from GitHub via gh api (avoids direct registry TLS issues)
fetch_md () {
  local ref="$1"
  local path="$2"
  # Get file contents (base64) from GitHub
  gh api "repos/kubernetes-csi/external-snapshotter/contents/${path}?ref=${ref}" --jq '.content' -r | base64 -d
}

echo "=== Fetch CHANGELOG-8.5.md ==="
CH85="$(fetch_md "v8.5.0" "CHANGELOG/CHANGELOG-8.5.md")"
echo "${CH85}" | head -n 60

echo ""
echo "=== Search CHANGELOG-8.5.md for security/CVE keywords ==="
echo "${CH85}" | rg -n -i "cve|security|vulnerability|fix|patched" | head -n 50 || true

echo ""
echo "=== Search CHANGELOG-8.5.md for VolumeGroupSnapshot / v1beta2 mentions ==="
echo "${CH85}" | rg -n -i "VolumeGroupSnapshot|v1beta2|beta2" | head -n 80 || true

echo ""
echo "=== Fetch CHANGELOG-8.4.md (context for VolumeGroupSnapshot support) ==="
CH84="$(fetch_md "v8.4.0" "CHANGELOG/CHANGELOG-8.4.md")"
echo "${CH84}" | head -n 60

echo ""
echo "=== Search CHANGELOG-8.4.md for VolumeGroupSnapshot / v1beta2 mentions ==="
echo "${CH84}" | rg -n -i "VolumeGroupSnapshot|v1beta2|beta2" | head -n 80 || true

echo ""
echo "=== Search CHANGELOG-8.4.md for security/CVE keywords ==="
echo "${CH84}" | rg -n -i "cve|security|vulnerability|fix|patched" | head -n 50 || true

echo ""
echo "=== Done ==="

Repository: openshift/csi-external-snapshotter

Length of output: 1554


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fetch_md () {
  local ref="$1"
  local path="$2"
  local b64
  b64="$(gh api "repos/kubernetes-csi/external-snapshotter/contents/${path}?ref=${ref}" --jq '.content')"
  echo "$b64" | tr -d '\n' | base64 -d
}

echo "=== Fetch CHANGELOG-8.5.md (first 60 lines) ==="
CH85="$(fetch_md "v8.5.0" "CHANGELOG/CHANGELOG-8.5.md")"
echo "$CH85" | head -n 60

echo ""
echo "=== Search CHANGELOG-8.5.md for security/CVE keywords ==="
echo "$CH85" | rg -n -i "cve|security|vulnerability|fix|patched" | head -n 50 || true

echo ""
echo "=== Search CHANGELOG-8.5.md for VolumeGroupSnapshot / v1beta2 mentions ==="
echo "$CH85" | rg -n -i "VolumeGroupSnapshot|v1beta2|beta2" | head -n 80 || true

echo ""
echo "=== Fetch CHANGELOG-8.4.md (first 60 lines) ==="
CH84="$(fetch_md "v8.4.0" "CHANGELOG/CHANGELOG-8.4.md")"
echo "$CH84" | head -n 60

echo ""
echo "=== Search CHANGELOG-8.4.md for VolumeGroupSnapshot / v1beta2 mentions ==="
echo "$CH84" | rg -n -i "VolumeGroupSnapshot|v1beta2|beta2" | head -n 80 || true

echo ""
echo "=== Search CHANGELOG-8.4.md for security/CVE keywords ==="
echo "$CH84" | rg -n -i "cve|security|vulnerability|fix|patched" | head -n 50 || true

Repository: openshift/csi-external-snapshotter

Length of output: 675


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml"
echo "=== File: $FILE (lines 1-140) ==="
nl -ba "$FILE" | sed -n '1,140p'

echo ""
echo "=== Search for key security/scheduling fields ==="
rg -n "securityContext|runAsNonRoot|readOnlyRootFilesystem|allowPrivilegeEscalation|hostPID|hostNetwork|hostIPC|privileged|capabilities:|automountServiceAccountToken|resources:|limits:|requests:|livenessProbe|readinessProbe|minReadySeconds|--retry|crd|interval|maxUnavailable|podAntiAffinity|topologySpreadConstraints" "$FILE" || true

Repository: openshift/csi-external-snapshotter

Length of output: 236


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml"
echo "=== File: $FILE ==="
wc -l "$FILE"
echo ""
echo "=== Show first 200 lines with line numbers ==="
cat -n "$FILE" | sed -n '1,200p'

echo ""
echo "=== Search for key security/scheduling fields ==="
rg -n "securityContext|runAsNonRoot|readOnlyRootFilesystem|allowPrivilegeEscalation|hostPID|hostNetwork|hostIPC|privileged|capabilities:|automountServiceAccountToken|resources:|limits:|requests:|livenessProbe|readinessProbe|minReadySeconds|--retry|crd|interval|maxUnavailable|podAntiAffinity|topologySpreadConstraints" "$FILE" || true

Repository: openshift/csi-external-snapshotter

Length of output: 2687


Confirm snapshot-controller downgrade image + security posture

  • deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml uses registry.k8s.io/sig-storage/snapshot-controller:v8.4.0; ensure this tag is present upstream, and that downgrading from v8.5.0 doesn’t reintroduce critical CVEs and still includes the HyperShift/VolumeGroupSnapshot v1beta2 handling fix.
  • The manifest lacks container resources and securityContext (e.g., runAsNonRoot, readOnlyRootFilesystem, drop capabilities, allowPrivilegeEscalation: false), has no liveness/readiness probes, and doesn’t set automountServiceAccountToken: false (unless required).
  • minReadySeconds: 35 matches the CRD availability retry rationale in the comments.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml` at line
37, Verify the snapshot-controller image tag
registry.k8s.io/sig-storage/snapshot-controller:v8.4.0 exists upstream and
document CVE/patch differences vs v8.5.0 (ensure the
HyperShift/VolumeGroupSnapshot v1beta2 fix remains); then harden the pod spec
that runs the snapshot controller by adding container-level resources, a
securityContext (runAsNonRoot: true, readOnlyRootFilesystem: true,
dropCapabilities: [ALL], allowPrivilegeEscalation: false), livenessProbe and
readinessProbe entries, and set automountServiceAccountToken: false on the
Pod/Deployment spec; preserve minReadySeconds: 35 as noted. Include these
changes around the container declaration that references the image line so
reviewers can find the updated pod/deployment spec.

Comment on lines +285 to 292
// check if the snapshot is being used for restore a PVC, if yes, do nothing
// and wait until PVC restoration finishes
if content != nil && ctrl.isVolumeBeingCreatedFromSnapshot(snapshot) {
klog.V(4).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent[%s]: snapshot is being used to restore a PVC", utils.SnapshotKey(snapshot))
ctrl.eventRecorder.Event(snapshot, v1.EventTypeWarning, "SnapshotDeletePending", "Snapshot is being used to restore a PVC")
return fmt.Errorf("snapshot %s is in use (being used to restore a PVC), will retry deletion", utils.SnapshotKey(snapshot))
// TODO(@xiangqian): should requeue this?
return nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Returning nil here can strand snapshots in terminating state.

Line 291 acknowledges a transient “delete pending” condition, but returning nil means the key is treated as handled and may not be retried promptly. This can leave finalizers stuck until a separate event happens.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/common-controller/snapshot_controller.go` around lines 285 - 292, The
code in checkandRemoveSnapshotFinalizersAndCheckandDeleteContent returns nil
when isVolumeBeingCreatedFromSnapshot(snapshot) is true, which prevents
immediate requeue and can leave the Snapshot stuck; change this to trigger a
requeue instead of treating it as handled — e.g., return a requeue signal/error
so the controller retries later (for example, return a small requeue error like
fmt.Errorf("snapshot in use for PVC restore, requeue") or use the controller's
existing requeue helper if one exists), keeping the check using
isVolumeBeingCreatedFromSnapshot and preserving the eventRecorder log.

Comment thread pkg/metrics/metrics.go
Comment on lines 299 to +311
func (opMgr *operationMetricsManager) scheduleOpsInFlightMetric(ctx context.Context) {
ticker := time.NewTicker(inFlightCheckInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
func() {
opMgr.mu.Lock()
defer opMgr.mu.Unlock()
opMgr.opInFlight.Set(float64(len(opMgr.cache)))
}()
default:
for range time.NewTicker(inFlightCheckInterval).C {
func() {
opMgr.mu.Lock()
defer opMgr.mu.Unlock()
opMgr.opInFlight.Set(float64(len(opMgr.cache)))
}()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="pkg/metrics/metrics.go"

echo "== Relevant block =="
nl -ba "$FILE" | sed -n '294,314p'

echo
echo "== Pattern check: nested ticker loop without inner ctx.Done case =="
rg -n 'for range time.NewTicker\(inFlightCheckInterval\)\.C|ctx\.Done\(\)|ticker\.Stop\(' "$FILE"

Repository: openshift/csi-external-snapshotter

Length of output: 160


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="pkg/metrics/metrics.go"

echo "== Relevant block (lines 294-314) =="
python3 - <<'PY'
path = "pkg/metrics/metrics.go"
start, end = 294, 314
with open(path, "r", encoding="utf-8") as f:
    for i, line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:4d}\t{line.rstrip()}")
PY

echo
echo "== Pattern check =="
rg -n 'for range time\.NewTicker\(inFlightCheckInterval\)\.C|ctx\.Done\(\)|ticker\.Stop\(' "$FILE" || true

Repository: openshift/csi-external-snapshotter

Length of output: 782


Fix in-flight metrics goroutine cancellation + ticker lifecycle leak (pkg/metrics/metrics.go:299-313)

  • ctx.Done() is only checked before entering the for range time.NewTicker(inFlightCheckInterval).C loop, so cancellation won’t stop the goroutine.
  • The ticker created at line 305 is never Stop()’d.
Proposed fix
 func (opMgr *operationMetricsManager) scheduleOpsInFlightMetric(ctx context.Context) {
-	for {
-		select {
-		case <-ctx.Done():
-			return
-		default:
-			for range time.NewTicker(inFlightCheckInterval).C {
-				func() {
-					opMgr.mu.Lock()
-					defer opMgr.mu.Unlock()
-					opMgr.opInFlight.Set(float64(len(opMgr.cache)))
-				}()
-			}
-		}
-	}
+	ticker := time.NewTicker(inFlightCheckInterval)
+	defer ticker.Stop()
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		case <-ticker.C:
+			opMgr.mu.Lock()
+			opMgr.opInFlight.Set(float64(len(opMgr.cache)))
+			opMgr.mu.Unlock()
+		}
+	}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (opMgr *operationMetricsManager) scheduleOpsInFlightMetric(ctx context.Context) {
ticker := time.NewTicker(inFlightCheckInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
func() {
opMgr.mu.Lock()
defer opMgr.mu.Unlock()
opMgr.opInFlight.Set(float64(len(opMgr.cache)))
}()
default:
for range time.NewTicker(inFlightCheckInterval).C {
func() {
opMgr.mu.Lock()
defer opMgr.mu.Unlock()
opMgr.opInFlight.Set(float64(len(opMgr.cache)))
}()
}
func (opMgr *operationMetricsManager) scheduleOpsInFlightMetric(ctx context.Context) {
ticker := time.NewTicker(inFlightCheckInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
opMgr.mu.Lock()
opMgr.opInFlight.Set(float64(len(opMgr.cache)))
opMgr.mu.Unlock()
}
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/metrics/metrics.go` around lines 299 - 311, The goroutine in
operationMetricsManager.scheduleOpsInFlightMetric creates a new time.Ticker in a
for-range and never stops it, and ctx.Done() is only checked outside that inner
loop; fix by creating a ticker once (ticker :=
time.NewTicker(inFlightCheckInterval)) and using a single select loop like: for
{ select { case <-ctx.Done(): ticker.Stop(); return; case <-ticker.C:
opMgr.mu.Lock(); opMgr.opInFlight.Set(float64(len(opMgr.cache)));
opMgr.mu.Unlock() } } so the ticker is stopped on cancellation and the goroutine
exits promptly.

Source: Coding guidelines

Comment thread pkg/utils/util.go
Comment on lines 405 to +406
// GetSecretReference for the group snapshot
func GetGroupSnapshotSecretReference(secretParams secretParamsMap, volumeGroupSnapshotClassParams map[string]string, groupSnapContentName string, volumeGroupSnapshot *groupsnapshotv1.VolumeGroupSnapshot) (*v1.SecretReference, error) {
func GetGroupSnapshotSecretReference(secretParams secretParamsMap, volumeGroupSnapshotClassParams map[string]string, groupSnapContentName string, volumeGroupSnapshot *crdv1beta2.VolumeGroupSnapshot) (*v1.SecretReference, error) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Avoid replacing the exported v1 helper signatures in place.

These are public pkg/utils helpers. Changing their parameter types from group-snapshot v1 objects to v1beta2 objects breaks compilation for any downstream caller that still passes the old types. Add v1beta2-specific entry points or compatibility shims instead of rewriting the existing exported signatures in place.

Based on learnings, changes must be backward compatible; old code should still compile and runtime behavior cannot change in breaking ways.

Also applies to: 505-506, 517-518, 532-533, 586-665

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/utils/util.go` around lines 405 - 406, The exported helper
GetGroupSnapshotSecretReference was changed to accept v1beta2 types, which
breaks downstream callers; revert the public signature to accept the original v1
types and restore its original behavior, and add a new v1beta2-specific entry
point (e.g., GetGroupSnapshotSecretReferenceV1Beta2 or a wrapper function) that
converts v1beta2 inputs to v1 or delegates to shared internal logic; apply the
same pattern for the other exported helpers you modified (the additional helpers
flagged in the comment) by keeping their original v1 signatures and adding
separate v1beta2 wrappers/shims that perform any necessary type conversion or
call into common unexported functions.

Source: Learnings

Comment thread pkg/webhook/webhook.go
Comment on lines 45 to 48
srv := &http.Server{
Handler: mux,
TLSConfig: tlsConfig,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 15 * time.Second,
Handler: mux,
TLSConfig: tlsConfig,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore HTTP server timeouts to avoid connection-hold DoS risk.

Lines 45-48 remove ReadTimeout/WriteTimeout/IdleTimeout, leaving the server vulnerable to slow or stalled connections consuming resources indefinitely.

Suggested fix
 import (
 	"context"
 	"crypto/tls"
 	"fmt"
 	"net/http"
+	"time"
@@
 	srv := &http.Server{
-		Handler:   mux,
-		TLSConfig: tlsConfig,
+		Handler:      mux,
+		TLSConfig:    tlsConfig,
+		ReadTimeout:  10 * time.Second,
+		WriteTimeout: 10 * time.Second,
+		IdleTimeout:  60 * time.Second,
 	}

As per coding guidelines: “context.Context for cancellation and timeouts.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
srv := &http.Server{
Handler: mux,
TLSConfig: tlsConfig,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 15 * time.Second,
Handler: mux,
TLSConfig: tlsConfig,
}
srv := &http.Server{
Handler: mux,
TLSConfig: tlsConfig,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/webhook/webhook.go` around lines 45 - 48, The http.Server instance
assigned to srv omits ReadTimeout/WriteTimeout/IdleTimeout, exposing the server
to connection-hold DoS; update the http.Server initialization (where srv is
constructed) to set sensible ReadTimeout, WriteTimeout, and IdleTimeout values
(e.g., seconds/minutes appropriate for your handlers) and ensure any
long-running operations respect context cancellation (use the request
context.Context in handler functions) so that connections/timeouts are enforced
and resources are not held indefinitely.

Source: Coding guidelines

Comment on lines +11 to +12
- uses: actions/checkout@v6
- uses: codespell-project/actions-codespell@master

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Supply chain security: Multiple workflows use unpinned GitHub Actions. Both codespell.yml and trivy.yaml switched from pinned commit hashes to floating references (@v6, @master). The shared root cause is a violation of dependency pinning requirements—all three action references should use full commit SHAs to prevent supply chain attacks via compromised upstream repositories.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@release-tools/.github/workflows/codespell.yml` around lines 11 - 12, The
workflow uses floating action references (actions/checkout@v6 and
codespell-project/actions-codespell@master); replace these with full commit SHAs
to pin dependencies and update any other workflows (e.g., trivy.yaml) that also
use unpinned refs. Locate the two uses in the workflow (the lines referencing
actions/checkout and codespell-project/actions-codespell) and change them to
their corresponding full commit SHA references (e.g.,
actions/checkout@<commit-sha> and
codespell-project/actions-codespell@<commit-sha>), ensuring you fetch the exact
commit SHAs from the actions' repositories and use those pinned SHAs
consistently across all workflows.

Source: Coding guidelines

@jsafrane

Copy link
Copy Markdown

/ok-to-test

@openshift-ci openshift-ci Bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Jun 11, 2026
@petr-muller

petr-muller commented Jun 11, 2026

Copy link
Copy Markdown
Member

/retitle TRT-2702: Revert "STOR-3004: Rebase external-snapshotter to v8.6.0"

@openshift-ci openshift-ci Bot changed the title Revert "STOR-3004: Rebase external-snapshotter to v8.6.0" TRT-2702: Revert "STOR-3004: Rebase external-snapshotter to v8.6.0" Jun 11, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 11, 2026

Copy link
Copy Markdown

@redhat-chai-bot: This pull request references TRT-2702 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

This reverts merge commit cab9af9 (PR #219).

Why

The v8.6.0 rebase changed the snapshot-controller to require VolumeGroupSnapshot CRDs at startup when CSIVolumeGroupSnapshot=true. In HyperShift hosted clusters, CRDs are installed asynchronously in the guest cluster, creating a race condition that causes 6–7 crash-loop restarts of csi-snapshot-controller before the CRDs become available.

This broke the 5.0 CI payload 5.0.0-0.ci-2026-06-11-001513 (rejected — baseline 5.0.0-0.ci-2026-06-10-181513 was Accepted).

Failing Jobs (100% failure rate)

  • hypershift-e2e-aks — 2/2 failures
  • hypershift-e2e-aws — 2/2 failures

Notes

The original PR's presubmit CI had no HyperShift coverage, so the race condition was undetected before merge. The rebase should be re-landed with a fix that makes the VolumeGroupSnapshot CRD dependency non-blocking at startup (e.g., retry loop or optional initialization).

/cc @rvagner78

Summary by CodeRabbit

Release Notes

  • Breaking Changes

  • Removed support for VolumeGroupSnapshot v1 API; v1beta2 is now required.

  • Chores

  • Updated Go toolchain to 1.25.x and Kubernetes dependencies to v0.30.0–v0.35.0.

  • Updated container image versions for csi-provisioner, csi-snapshotter, and hostpathplugin.

  • Updated CRD configurations for VolumeGroupSnapshot resources with conversion webhook support.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

This reverts merge commit cab9af9 (PR openshift#219).

The v8.6.0 rebase changed the snapshot-controller to require VolumeGroupSnapshot
CRDs at startup when CSIVolumeGroupSnapshot=true. In HyperShift hosted clusters,
CRDs are installed asynchronously in the guest cluster, creating a race condition
that causes 6-7 crash-loop restarts of csi-snapshot-controller.

This broke payload 5.0.0-0.ci-2026-06-11-001513 (hypershift-e2e-aks and
hypershift-e2e-aws both at 100% failure rate).
@petr-muller

Copy link
Copy Markdown
Member

/payload-job periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aks periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aws-ovn

@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

@petr-muller: trigger 2 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aks
  • periodic-ci-openshift-hypershift-release-5.0-periodics-e2e-aws-ovn

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/ecc294a0-659a-11f1-9ae7-703c60bf7b4a-0

@jsafrane

Copy link
Copy Markdown

/lgtm
/approve

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 11, 2026
@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jsafrane, redhat-chai-bot

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 11, 2026
@jsafrane

jsafrane commented Jun 11, 2026

Copy link
Copy Markdown

/override ci/prow/unit

test-subtree checks that content of release-tools is modified only by git subtree. The revert modifies it via git revert.

@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

@jsafrane: Overrode contexts on behalf of jsafrane: ci/prow/unit

Details

In response to this:

/override ci/prow/unit

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@petr-muller

Copy link
Copy Markdown
Member

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jun 11, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@petr-muller: This PR has been marked as verified by https://redhat-internal.slack.com/archives/C01CQA76KMX/p1781185292239609?thread_ts=1781181693.651789&cid=C01CQA76KMX.

Details

In response to this:

/verified by https://redhat-internal.slack.com/archives/C01CQA76KMX/p1781185292239609?thread_ts=1781181693.651789&cid=C01CQA76KMX

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@petr-muller

Copy link
Copy Markdown
Member

/override ci/prow/e2e-aws-csi
/override ci/prow/e2e-gcp-csi
/override ci/prow/e2e-vsphere
/override ci/prow/e2e-vsphere-csi

@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

@petr-muller: Overrode contexts on behalf of petr-muller: ci/prow/e2e-aws-csi, ci/prow/e2e-gcp-csi, ci/prow/e2e-vsphere, ci/prow/e2e-vsphere-csi

Details

In response to this:

/override ci/prow/e2e-aws-csi
/override ci/prow/e2e-gcp-csi
/override ci/prow/e2e-vsphere
/override ci/prow/e2e-vsphere-csi

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@petr-muller

petr-muller commented Jun 11, 2026

Copy link
Copy Markdown
Member

We are confident the reverted PR was the TRT-2702 culprit, so I'm expediting the merge so the payloads heal

@openshift-merge-bot openshift-merge-bot Bot merged commit e695e2b into openshift:master Jun 11, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants