Skip to content

NO-JIRA: update func from library-go#724

Open
gangwgr wants to merge 2 commits into
openshift:mainfrom
gangwgr:bump-test-cases
Open

NO-JIRA: update func from library-go#724
gangwgr wants to merge 2 commits into
openshift:mainfrom
gangwgr:bump-test-cases

Conversation

@gangwgr

@gangwgr gangwgr commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Chores

    • Updated a bundled dependency to a newer version for Go module consistency.
  • Tests

    • Refactored end-to-end encryption, encryption rotation, and KMS encryption scenarios to use shared encryption helpers and common target-group/route assertion utilities.
    • Standardized client setup and namespace create/delete flows across encryption tests, and aligned route lifecycle creation and encryption-state verification logic with the shared library implementation.
    • Removed the dedicated per-library encryption helper implementation in favor of the shared equivalents.

@openshift-ci

openshift-ci Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 29, 2026
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR bumps library-go and migrates encryption e2e tests from local operatorencryption helpers to shared library-go helpers. The rotation test also switches to an OpenShift API operator client for unsupported config updates.

Changes

Encryption test migration

Layer / File(s) Summary
Dependency update
go.mod
github.com/openshift/library-go is updated, and go.etcd.io/etcd/client/v3 v3.6.5 // indirect is added.
Shared encryption helpers
test/library/encryption/*, test/e2e-encryption-kms/encryption_kms.go, test/e2e-encryption/encryption_test.go, test/e2e/operator_test.go
The shared encryption helper package is removed, and the KMS, encryption, and operator e2e tests switch target selection, route creation, route assertions, and client acquisition to library-go equivalents.
Rotation client flow
test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
The rotation test builds its kubeconfig with library-go, creates an operatorv1client, updates unsupported config through that client, and uses library-go route helpers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: everettraven


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 3 warnings, 1 inconclusive)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error Changed e2e tests now call library.GetClients, which goes through NewClientConfigForTest and logs config.Host to stdout. Remove or redact the host print in vendor/github.com/openshift/library-go/test/library/client.go (or avoid that helper in tests).
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning Some modified tests use context.TODO() for cluster API calls and bare require.NoError/t.Fatal assertions, so they lack per-op timeouts and useful failure context. Replace context.TODO() with t.Context()/context.WithTimeout for kube calls, and add messages to error assertions (e.g. require.NoError(t, err, "create namespace")).
Microshift Test Compatibility ⚠️ Warning FAIL: these e2e encryption tests still use config.openshift.io APIServer and operator.openshift.io OpenShiftAPIServers, with no MicroShift skip/tag. Add [Skipped:MicroShift] or suitable [apigroup:...] labels, or guard with exutil.IsMicroShiftCluster(), and keep these specs out of MicroShift CI.
Title check ❓ Inconclusive The title is generic and doesn’t clearly convey the main change: refactoring e2e encryption tests to use shared library-go helpers. Use a specific title like 'Refactor encryption e2e tests to use shared library-go helpers'.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Touched Ginkgo titles are static strings; no dynamic pod/namespace/node/UUID/time values appear in test names.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The changed e2e tests only create namespaces/routes and validate encryption; I found no node-count, scheduling, drain, or HA assumptions, and no SNO skip was needed.
Topology-Aware Scheduling Compatibility ✅ Passed The PR only updates tests, deletes test helpers, and bumps go.mod; no deployment manifests, controller code, or scheduling fields are modified.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes were added: touched entrypoints/TestMain have no prints, and the only fmt.Printf is in a helper called from normal test bodies.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The changed e2e tests only use cluster clients and internal Route/namespace helpers; no hardcoded IPv4, localhost, public hosts, or external URLs were found.
No-Weak-Crypto ✅ Passed Touched files only swap encryption test helpers; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret comparisons were introduced.
Container-Privileges ✅ Passed Touched files are go.mod and Go e2e tests; scans found no privileged/hostPID/hostNetwork/allowPrivilegeEscalation settings, and no manifests were changed.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@gangwgr

gangwgr commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-operator-encryption-kms

@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: 2

🧹 Nitpick comments (1)
test/e2e-encryption-kms/encryption_kms.go (1)

60-65: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Use the existing test context and callback inputs here.

context.TODO() drops cancellation from the enclosing test, and reopening clients inside the callback is unnecessary when the scenario already passes them in. As per path instructions, Go security (prodsec-skills): context.Context for cancellation and timeouts.

Suggested fix
-		CreateResourceFunc: func(t testing.TB, _ library.ClientSet, namespace string) runtime.Object {
-			return library.CreateAndStoreRouteOfLife(context.TODO(), t, library.GetClients(t), ns)
+		CreateResourceFunc: func(t testing.TB, cs library.ClientSet, namespace string) runtime.Object {
+			return library.CreateAndStoreRouteOfLife(ctx, t, cs, namespace)
 		},
 		AssertResourceEncryptedFunc:    library.AssertRouteOfLifeEncrypted,
 		AssertResourceNotEncryptedFunc: library.AssertRouteOfLifeNotEncrypted,
-		ResourceFunc:                   func(t testing.TB, _ string) runtime.Object { return library.RouteOfLife(ns) },
+		ResourceFunc:                   func(t testing.TB, namespace string) runtime.Object { return library.RouteOfLife(namespace) },

Also applies to: 97-102

🤖 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 `@test/e2e-encryption-kms/encryption_kms.go` around lines 60 - 65, The resource
creation callback is ignoring the existing test context and passed-in client set
by using context.TODO() and reopening clients via library.GetClients(t), which
drops cancellation and duplicates work. Update the CreateResourceFunc closures
for RouteOfLife to use the callback’s testing.TB and provided
library.ClientSet/context inputs instead of creating new clients, and thread the
existing context through the call to library.CreateAndStoreRouteOfLife so
cancellation and timeouts are preserved.

Source: Path instructions

🤖 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 `@go.mod`:
- Line 147: The go.mod replace for github.com/openshift/library-go currently
points to a personal fork, which should be removed or justified. Update the
module dependency so it uses the upstream OpenShift-maintained
github.com/openshift/library-go chain again, and drop the replace entry once the
helper change is upstreamed; if the fork must remain temporarily, document the
fork owner and synchronization plan near the dependency management area.

In `@test/e2e-encryption-kms/encryption_kms.go`:
- Line 48: The deferred namespace cleanup in the e2e KMS test drops the error
returned by Namespace Delete, so update the defer around
cs.Kube.CoreV1().Namespaces().Delete to check and handle any delete failure
instead of ignoring it; apply the same fix to the other deferred namespace
delete in this test file as well.

---

Nitpick comments:
In `@test/e2e-encryption-kms/encryption_kms.go`:
- Around line 60-65: The resource creation callback is ignoring the existing
test context and passed-in client set by using context.TODO() and reopening
clients via library.GetClients(t), which drops cancellation and duplicates work.
Update the CreateResourceFunc closures for RouteOfLife to use the callback’s
testing.TB and provided library.ClientSet/context inputs instead of creating new
clients, and thread the existing context through the call to
library.CreateAndStoreRouteOfLife so cancellation and timeouts are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: a0604f00-b226-45d9-93f8-f19eb459cd3a

📥 Commits

Reviewing files that changed from the base of the PR and between ec1966f and 8b7c7c2.

⛔ Files ignored due to path filters (7)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/library-go/test/library/encryption/assertion_auth.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/assertion_oas.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/helpers_auth.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/helpers_oas.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (4)
  • _output/golang-versions
  • _output/named-golang-versions
  • go.mod
  • test/e2e-encryption-kms/encryption_kms.go

Comment thread go.mod Outdated
_, err := cs.Kube.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
require.NoError(t, err)
defer cs.KubeClient.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
defer cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Check the deferred namespace delete error.

Delete failures are currently dropped, which can leak namespaces and make later e2e runs flaky. As per path instructions, Go security (prodsec-skills): Never ignore error returns.

Suggested fix
- defer cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
+ t.Cleanup(func() {
+ 	require.NoError(t, cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}))
+ })

Also applies to: 85-85

🧰 Tools
🪛 golangci-lint (2.12.2)

[error] 48-48: Error return value of (k8s.io/client-go/kubernetes/typed/core/v1.NamespaceInterface).Delete is not checked

(errcheck)

🤖 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 `@test/e2e-encryption-kms/encryption_kms.go` at line 48, The deferred namespace
cleanup in the e2e KMS test drops the error returned by Namespace Delete, so
update the defer around cs.Kube.CoreV1().Namespaces().Delete to check and handle
any delete failure instead of ignoring it; apply the same fix to the other
deferred namespace delete in this test file as well.

Sources: Path instructions, Linters/SAST tools

ResourceFunc: func(t testing.TB, _ string) runtime.Object { return operatorencryption.RouteOfLife(t, ns) },
AssertResourceEncryptedFunc: library.AssertRouteOfLifeEncrypted,
AssertResourceNotEncryptedFunc: library.AssertRouteOfLifeNotEncrypted,
ResourceFunc: func(t testing.TB, _ string) runtime.Object { return library.RouteOfLife(ns) },

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to update RouteOfLife to accept t.

@ardaguclu

Copy link
Copy Markdown
Member

We are making changes for all encryption types. It would be better to run all encryption jobs.

@gangwgr gangwgr marked this pull request as ready for review June 29, 2026 12:36
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 29, 2026
@openshift-ci openshift-ci Bot requested review from everettraven and rh-roman June 29, 2026 12:41

@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: 1

🤖 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 `@test/e2e-encryption-kms/encryption_kms.go`:
- Around line 60-62: The RouteOfLife resource creation is discarding the test
context, so the client calls won’t respect Ginkgo cancellation and timeout
behavior. Update the CreateResourceFunc and the RouteOfLife setup path to thread
through the existing ctx instead of creating a fresh context, using the same
context value when calling library.CreateAndStoreRouteOfLife and any related
client helpers. Make the fix in the test helpers around CreateResourceFunc and
the RouteOfLife creation call so context is consistently propagated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 485d3a0b-3dca-404e-b4de-1bbb947a794f

📥 Commits

Reviewing files that changed from the base of the PR and between 8b7c7c2 and 9564f71.

⛔ Files ignored due to path filters (7)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/library-go/test/library/encryption/assertion_auth.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/assertion_oas.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/helpers_auth.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/helpers_oas.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (4)
  • _output/golang-versions
  • _output/named-golang-versions
  • go.mod
  • test/e2e-encryption-kms/encryption_kms.go
✅ Files skipped from review due to trivial changes (2)
  • _output/named-golang-versions
  • _output/golang-versions
🚧 Files skipped from review as they are similar to previous changes (1)
  • go.mod

Comment on lines 60 to 62
CreateResourceFunc: func(t testing.TB, _ library.ClientSet, namespace string) runtime.Object {
return operatorencryption.CreateAndStoreRouteOfLife(context.TODO(), t, operatorencryption.GetClients(t), ns)
return library.CreateAndStoreRouteOfLife(context.TODO(), t, library.GetClients(t), ns)
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Propagate the test context into RouteOfLife creation.

Line 61 and Line 98 discard the test ctx, so these client calls won't honor the Ginkgo cancellation/timeout path.

Suggested fix
-			return library.CreateAndStoreRouteOfLife(context.TODO(), t, library.GetClients(t), ns)
+			return library.CreateAndStoreRouteOfLife(ctx, t, library.GetClients(t), ns)

As per path instructions, Go security (prodsec-skills): context.Context for cancellation and timeouts.

Also applies to: 97-99

🤖 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 `@test/e2e-encryption-kms/encryption_kms.go` around lines 60 - 62, The
RouteOfLife resource creation is discarding the test context, so the client
calls won’t respect Ginkgo cancellation and timeout behavior. Update the
CreateResourceFunc and the RouteOfLife setup path to thread through the existing
ctx instead of creating a fresh context, using the same context value when
calling library.CreateAndStoreRouteOfLife and any related client helpers. Make
the fix in the test helpers around CreateResourceFunc and the RouteOfLife
creation call so context is consistently propagated.

Source: Path instructions

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 30, 2026
@gangwgr gangwgr force-pushed the bump-test-cases branch from 9564f71 to 26f18dc Compare July 1, 2026 04:26
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 1, 2026
@gangwgr gangwgr changed the title update func from library-go NO-JIRA: update func from library-go Jul 1, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 1, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@gangwgr: This pull request explicitly references no jira issue.

Details

In response to this:

Summary by CodeRabbit

  • Chores

  • Updated a bundled dependency to a newer version.

  • Tests

  • Modernized end-to-end encryption test setup to use shared encryption helpers, improving consistency and maintainability of encryption-related test coverage.

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.

@gangwgr

gangwgr commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@ardaguclu

Copy link
Copy Markdown
Member

Overall sounds good to me. But we need to see all the jobs green.

"k8s.io/apimachinery/pkg/runtime"

"github.com/openshift/cluster-openshift-apiserver-operator/pkg/operator/operatorclient"
operatorencryption "github.com/openshift/cluster-openshift-apiserver-operator/test/library/encryption"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we remove unused files in second commit?.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated

operatorv1client "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1"
"github.com/openshift/cluster-openshift-apiserver-operator/pkg/operator/operatorclient"
operatorencryption "github.com/openshift/cluster-openshift-apiserver-operator/test/library/encryption"
testlibrary "github.com/openshift/cluster-openshift-apiserver-operator/test/library"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we get rid of this dependency?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated

@gangwgr gangwgr force-pushed the bump-test-cases branch 2 times, most recently from 719519f to 5c86635 Compare July 1, 2026 09:21

@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: 2

🧹 Nitpick comments (2)
test/e2e-encryption/encryption_test.go (1)

63-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

CreateResourceFunc ignores the injected ClientSet and builds a new one instead.

CreateResourceFunc receives a library.ClientSet argument but discards it (_) and calls library.GetClients(t) again, even though cs is already available in the enclosing scope (line 49). This creates a redundant client for no benefit and diverges from the parameter contract the scenario framework provides.

♻️ Proposed fix
-		CreateResourceFunc: func(t testing.TB, _ library.ClientSet, namespace string) runtime.Object {
-			return library.CreateAndStoreRouteOfLife(context.TODO(), t, library.GetClients(t), ns)
+		CreateResourceFunc: func(t testing.TB, clientSet library.ClientSet, namespace string) runtime.Object {
+			return library.CreateAndStoreRouteOfLife(context.TODO(), t, clientSet, ns)
 		},
🤖 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 `@test/e2e-encryption/encryption_test.go` around lines 63 - 71,
CreateResourceFunc is ignoring the injected ClientSet and unnecessarily calling
library.GetClients again. Update the CreateResourceFunc closure to use the
provided client set parameter instead of discarding it, matching the scenario
contract and avoiding redundant client creation. Keep the fix localized to the
CreateResourceFunc and, if needed, the related ResourceFunc usage in this test
setup.
test/e2e-encryption-rotation/e2e-encryption-rotation_test.go (1)

58-65: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

CreateResourceFunc ignores its provided ClientSet, inconsistent with GetRawResourceFunc.

CreateResourceFunc discards the injected library.ClientSet and calls library.GetClients(t) again to build a new client, whereas the sibling GetRawResourceFunc correctly uses the clientSet parameter it receives. This inconsistency creates an unnecessary redundant client and diverges from the pattern used two lines below.

♻️ Proposed fix
-		CreateResourceFunc: func(t testing.TB, _ library.ClientSet, _ string) runtime.Object {
-			return library.CreateAndStoreRouteOfLife(ctx, t, library.GetClients(t), ns)
+		CreateResourceFunc: func(t testing.TB, clientSet library.ClientSet, _ string) runtime.Object {
+			return library.CreateAndStoreRouteOfLife(ctx, t, clientSet, ns)
 		},
🤖 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 `@test/e2e-encryption-rotation/e2e-encryption-rotation_test.go` around lines 58
- 65, CreateResourceFunc is ignoring the injected ClientSet and rebuilding
clients with library.GetClients(t), which is inconsistent with
GetRawResourceFunc. Update the CreateResourceFunc closure in
e2e-encryption-rotation_test.go to use its clientSet parameter and pass that
through to library.CreateAndStoreRouteOfLife, keeping the resource creation path
aligned with the existing ClientSet-based pattern.
🤖 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 `@test/e2e-encryption-rotation/e2e-encryption-rotation_test.go`:
- Around line 29-49: The namespace cleanup and operator config update in the
test need to handle errors robustly. In the deferred Namespace Delete call after
creating ns, capture and check the delete error instead of ignoring it. In
updateUnsupportedConfig, replace the plain Get→mutate→Update flow on
operatorClient.OpenShiftAPIServers().Get/Update with a retry-on-conflict loop so
updates to the OpenShiftAPIServer “cluster” object are retried if Spec changes
between reads. Use the existing updateUnsupportedConfig helper and the
operatorClient/OpenShiftAPIServers symbols to keep the fix localized.

In `@test/e2e-encryption/encryption_test.go`:
- Around line 48-54: The deferred namespace cleanup in the encryption e2e test
ignores the error returned by cs.Kube.CoreV1().Namespaces().Delete, which
violates errcheck expectations. Update the defer after the namespace Create call
to handle the Delete return value explicitly, using the same ctx and namespace
identifier in the test setup, and route any cleanup failure through the test
helper/assertion pattern used in encryption_test.go so the error is not silently
discarded.

---

Nitpick comments:
In `@test/e2e-encryption-rotation/e2e-encryption-rotation_test.go`:
- Around line 58-65: CreateResourceFunc is ignoring the injected ClientSet and
rebuilding clients with library.GetClients(t), which is inconsistent with
GetRawResourceFunc. Update the CreateResourceFunc closure in
e2e-encryption-rotation_test.go to use its clientSet parameter and pass that
through to library.CreateAndStoreRouteOfLife, keeping the resource creation path
aligned with the existing ClientSet-based pattern.

In `@test/e2e-encryption/encryption_test.go`:
- Around line 63-71: CreateResourceFunc is ignoring the injected ClientSet and
unnecessarily calling library.GetClients again. Update the CreateResourceFunc
closure to use the provided client set parameter instead of discarding it,
matching the scenario contract and avoiding redundant client creation. Keep the
fix localized to the CreateResourceFunc and, if needed, the related ResourceFunc
usage in this test setup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 06957471-4f7a-4f4b-8e06-328d65a60811

📥 Commits

Reviewing files that changed from the base of the PR and between 26f18dc and 5c86635.

⛔ Files ignored due to path filters (24)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/client-go/route/applyconfigurations/internal/internal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/localobjectreference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/route.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheader.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactions.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactionunion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaders.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routeingress.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routeingresscondition.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routeport.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routesethttpheader.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routespec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routestatus.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routetargetreference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/tlsconfig.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/generated_expansion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/scenarios.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (6)
  • go.mod
  • test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
  • test/e2e-encryption/encryption_test.go
  • test/e2e/operator_test.go
  • test/library/encryption/assertion.go
  • test/library/encryption/helpers.go
💤 Files with no reviewable changes (2)
  • test/library/encryption/assertion.go
  • test/library/encryption/helpers.go

Comment on lines +29 to 49
cs := library.GetClients(t)

ns := fmt.Sprintf("test-encryption-on-off-%s", rand.String(4))
_, err := cs.KubeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
_, err := cs.Kube.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
require.NoError(t, err)
defer cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})

kubeConfig, err := librarygo.NewClientConfigForTest()
require.NoError(t, err)
operatorClient, err := operatorv1client.NewForConfig(kubeConfig)
require.NoError(t, err)
defer cs.KubeClient.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})

updateUnsupportedConfig := func(raw []byte) error {
cs := operatorencryption.GetClients(t)
apiServerOperator, err := cs.OperatorClient.Get(ctx, "cluster", metav1.GetOptions{})
apiServerOperator, err := operatorClient.OpenShiftAPIServers().Get(ctx, "cluster", metav1.GetOptions{})
if err != nil {
return err
}
apiServerOperator.Spec.UnsupportedConfigOverrides.Raw = raw
_, err = cs.OperatorClient.Update(ctx, apiServerOperator, metav1.UpdateOptions{})
_, err = operatorClient.OpenShiftAPIServers().Update(ctx, apiServerOperator, metav1.UpdateOptions{})
return err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Unchecked error on deferred namespace delete, and Get/Update without conflict retry.

Two issues in this block:

  1. Line 34: the deferred Delete error is unchecked (same errcheck finding as in encryption_test.go). Per path instructions, error returns should not be ignored.
  2. Lines 41-49: updateUnsupportedConfig does a plain Get→mutate→Update against the OpenShiftAPIServer operator object with no conflict retry. If the operator or another actor updates Spec between the Get and Update (a real possibility for a live operator object during a rotation test), the Update will fail with a conflict and the test will flake instead of retrying.
🩹 Proposed fix for the conflict retry
 	updateUnsupportedConfig := func(raw []byte) error {
-		apiServerOperator, err := operatorClient.OpenShiftAPIServers().Get(ctx, "cluster", metav1.GetOptions{})
-		if err != nil {
-			return err
-		}
-		apiServerOperator.Spec.UnsupportedConfigOverrides.Raw = raw
-		_, err = operatorClient.OpenShiftAPIServers().Update(ctx, apiServerOperator, metav1.UpdateOptions{})
-		return err
+		return retry.RetryOnConflict(retry.DefaultRetry, func() error {
+			apiServerOperator, err := operatorClient.OpenShiftAPIServers().Get(ctx, "cluster", metav1.GetOptions{})
+			if err != nil {
+				return err
+			}
+			apiServerOperator.Spec.UnsupportedConfigOverrides.Raw = raw
+			_, err = operatorClient.OpenShiftAPIServers().Update(ctx, apiServerOperator, metav1.UpdateOptions{})
+			return err
+		})
 	}
🧰 Tools
🪛 golangci-lint (2.12.2)

[error] 34-34: Error return value of (k8s.io/client-go/kubernetes/typed/core/v1.NamespaceInterface).Delete is not checked

(errcheck)

🤖 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 `@test/e2e-encryption-rotation/e2e-encryption-rotation_test.go` around lines 29
- 49, The namespace cleanup and operator config update in the test need to
handle errors robustly. In the deferred Namespace Delete call after creating ns,
capture and check the delete error instead of ignoring it. In
updateUnsupportedConfig, replace the plain Get→mutate→Update flow on
operatorClient.OpenShiftAPIServers().Get/Update with a retry-on-conflict loop so
updates to the OpenShiftAPIServer “cluster” object are retried if Spec changes
between reads. Use the existing updateUnsupportedConfig helper and the
operatorClient/OpenShiftAPIServers symbols to keep the fix localized.

Sources: Path instructions, Linters/SAST tools

Comment on lines 48 to +54
ctx := context.TODO()
cs := operatorencryption.GetClients(t)
cs := library.GetClients(t)

ns := fmt.Sprintf("test-encryption-on-off-%s", rand.String(4))
_, err := cs.KubeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
_, err := cs.Kube.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
require.NoError(t, err)
defer cs.KubeClient.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
defer cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Unchecked error on deferred namespace delete.

Static analysis flags the deferred Delete call's error as unchecked (errcheck). Per path instructions, Go code should never ignore error returns.

🩹 Proposed fix
-	defer cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
+	defer func() {
+		if err := cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}); err != nil {
+			t.Logf("failed to delete namespace %q: %v", ns, err)
+		}
+	}()
📝 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
ctx := context.TODO()
cs := operatorencryption.GetClients(t)
cs := library.GetClients(t)
ns := fmt.Sprintf("test-encryption-on-off-%s", rand.String(4))
_, err := cs.KubeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
_, err := cs.Kube.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
require.NoError(t, err)
defer cs.KubeClient.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
defer cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
ctx := context.TODO()
cs := library.GetClients(t)
ns := fmt.Sprintf("test-encryption-on-off-%s", rand.String(4))
_, err := cs.Kube.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
require.NoError(t, err)
defer func() {
if err := cs.Kube.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}); err != nil {
t.Logf("failed to delete namespace %q: %v", ns, err)
}
}()
🧰 Tools
🪛 golangci-lint (2.12.2)

[error] 54-54: Error return value of (k8s.io/client-go/kubernetes/typed/core/v1.NamespaceInterface).Delete is not checked

(errcheck)

🤖 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 `@test/e2e-encryption/encryption_test.go` around lines 48 - 54, The deferred
namespace cleanup in the encryption e2e test ignores the error returned by
cs.Kube.CoreV1().Namespaces().Delete, which violates errcheck expectations.
Update the defer after the namespace Create call to handle the Delete return
value explicitly, using the same ctx and namespace identifier in the test setup,
and route any cleanup failure through the test helper/assertion pattern used in
encryption_test.go so the error is not silently discarded.

Sources: Path instructions, Linters/SAST tools

@gangwgr gangwgr force-pushed the bump-test-cases branch from 5c86635 to 1d75084 Compare July 1, 2026 09:40

@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.

🧹 Nitpick comments (1)
test/e2e-encryption/encryption_test.go (1)

67-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant client creation.

library.GetClients(t) is called again here despite cs already being available in the enclosing scope from Line 49.

♻️ Reuse outer client set
-			return library.CreateAndStoreRouteOfLife(context.TODO(), t, library.GetClients(t), ns)
+			return library.CreateAndStoreRouteOfLife(context.TODO(), t, cs, ns)
🤖 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 `@test/e2e-encryption/encryption_test.go` at line 67, Reuse the existing client
set from the enclosing scope instead of calling library.GetClients(t) again in
the CreateAndStoreRouteOfLife path. Update the test logic around the
CreateAndStoreRouteOfLife invocation to pass cs directly, keeping the client
initialization centralized and avoiding redundant client creation.
🤖 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.

Nitpick comments:
In `@test/e2e-encryption/encryption_test.go`:
- Line 67: Reuse the existing client set from the enclosing scope instead of
calling library.GetClients(t) again in the CreateAndStoreRouteOfLife path.
Update the test logic around the CreateAndStoreRouteOfLife invocation to pass cs
directly, keeping the client initialization centralized and avoiding redundant
client creation.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: e5e2aaf6-ee17-4bb9-b68f-f62121413a7a

📥 Commits

Reviewing files that changed from the base of the PR and between 5c86635 and 1d75084.

⛔ Files ignored due to path filters (24)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/client-go/route/applyconfigurations/internal/internal.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/localobjectreference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/route.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheader.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactions.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaderactionunion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routehttpheaders.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routeingress.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routeingresscondition.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routeport.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routesethttpheader.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routespec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routestatus.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/routetargetreference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/applyconfigurations/route/v1/tlsconfig.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/scheme/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/generated_expansion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/client-go/route/clientset/versioned/typed/route/v1/route_client.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/test/library/encryption/scenarios.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (6)
  • go.mod
  • test/e2e-encryption-rotation/e2e-encryption-rotation_test.go
  • test/e2e-encryption/encryption_test.go
  • test/e2e/operator_test.go
  • test/library/encryption/assertion.go
  • test/library/encryption/helpers.go
💤 Files with no reviewable changes (2)
  • test/library/encryption/helpers.go
  • test/library/encryption/assertion.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/operator_test.go

@gangwgr

gangwgr commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-operator-encryption-aescbc

@ardaguclu

Copy link
Copy Markdown
Member

/approve
I think we may need lgtm from other folks about the direction

@openshift-ci

openshift-ci Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ardaguclu

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 Jul 1, 2026
@tjungblu

tjungblu commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

/lgtm

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

gangwgr commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/verified by ci runs

@openshift-ci-robot

Copy link
Copy Markdown

@gangwgr: This PR has been marked as verified by ci runs.

Details

In response to this:

/verified by ci runs

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-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jul 2, 2026
@gangwgr

gangwgr commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@gangwgr gangwgr force-pushed the bump-test-cases branch from 1d75084 to 29796fb Compare July 2, 2026 07:29
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Jul 2, 2026
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jul 2, 2026
@gangwgr gangwgr force-pushed the bump-test-cases branch from 29796fb to 8e52c22 Compare July 2, 2026 07:32
@tjungblu

tjungblu commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

/lgtm

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

gangwgr commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/test

@gangwgr

gangwgr commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-operator-encryption-rotation-aescbc

@gangwgr

gangwgr commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-operator-encryption-rotation-aesgcm

@gangwgr

gangwgr commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-operator-encryption-aesgcm

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants