-
Notifications
You must be signed in to change notification settings - Fork 532
OCPBUGS-100140: bracket IPv6 in OAuth issuer and callback URLs #9120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| package kas | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "testing" | ||
|
|
||
| . "github.com/onsi/gomega" | ||
|
|
||
| hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" | ||
| "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/infra" | ||
| controlplanecomponent "github.com/openshift/hypershift/support/controlplane-component" | ||
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
|
|
@@ -16,10 +18,15 @@ import ( | |
| func TestAdaptOauthMetadata(t *testing.T) { | ||
| t.Parallel() | ||
| tests := []struct { | ||
| name string | ||
| cfg *corev1.ConfigMap | ||
| wantErr bool | ||
| errSubstr string | ||
| name string | ||
| cfg *corev1.ConfigMap | ||
| oauthHost string | ||
| oauthPort int32 | ||
| wantErr bool | ||
| errSubstr string | ||
| wantIssuer string | ||
| wantAuthz string | ||
| wantToken string | ||
| }{ | ||
| { | ||
| name: "When ConfigMap contains invalid JSON, it should return an unmarshal error", | ||
|
|
@@ -31,6 +38,45 @@ func TestAdaptOauthMetadata(t *testing.T) { | |
| wantErr: true, | ||
| errSubstr: "failed to unmarshal oauth metadata", | ||
| }, | ||
| { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the project convention for test names is "When ..., it should ...". For example:
|
||
| name: "When OAuth host is IPv4, it should leave issuer URLs unbracketed", | ||
| cfg: &corev1.ConfigMap{ | ||
| Data: map[string]string{ | ||
| OauthMetadataConfigKey: `{}`, | ||
| }, | ||
| }, | ||
| oauthHost: "192.0.2.10", | ||
| oauthPort: 32047, | ||
| wantIssuer: "https://192.0.2.10:32047", | ||
| wantAuthz: "https://192.0.2.10:32047/oauth/authorize", | ||
| wantToken: "https://192.0.2.10:32047/oauth/token", | ||
| }, | ||
| { | ||
| name: "When OAuth host is IPv6, it should bracket the address", | ||
| cfg: &corev1.ConfigMap{ | ||
| Data: map[string]string{ | ||
| OauthMetadataConfigKey: `{}`, | ||
| }, | ||
| }, | ||
| oauthHost: "fd2e:6f44:5dd8:c956::14", | ||
| oauthPort: 32047, | ||
| wantIssuer: "https://[fd2e:6f44:5dd8:c956::14]:32047", | ||
| wantAuthz: "https://[fd2e:6f44:5dd8:c956::14]:32047/oauth/authorize", | ||
| wantToken: "https://[fd2e:6f44:5dd8:c956::14]:32047/oauth/token", | ||
| }, | ||
| { | ||
| name: "When OAuth host is a hostname, it should leave issuer URLs unbracketed", | ||
| cfg: &corev1.ConfigMap{ | ||
| Data: map[string]string{ | ||
| OauthMetadataConfigKey: `{}`, | ||
| }, | ||
| }, | ||
| oauthHost: "oauth.example.com", | ||
| oauthPort: 443, | ||
| wantIssuer: "https://oauth.example.com:443", | ||
| wantAuthz: "https://oauth.example.com:443/oauth/authorize", | ||
| wantToken: "https://oauth.example.com:443/oauth/token", | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
|
|
@@ -41,15 +87,25 @@ func TestAdaptOauthMetadata(t *testing.T) { | |
| Context: t.Context(), | ||
| HCP: &hyperv1.HostedControlPlane{}, | ||
| Client: fake.NewClientBuilder().Build(), | ||
| InfraStatus: infra.InfrastructureStatus{ | ||
| OAuthHost: tt.oauthHost, | ||
| OAuthPort: tt.oauthPort, | ||
| }, | ||
| } | ||
|
|
||
| err := adaptOauthMetadata(cpContext, tt.cfg) | ||
| if tt.wantErr { | ||
| g.Expect(err).To(HaveOccurred()) | ||
| g.Expect(err.Error()).To(ContainSubstring(tt.errSubstr)) | ||
| } else { | ||
| g.Expect(err).ToNot(HaveOccurred()) | ||
| return | ||
| } | ||
|
|
||
| g.Expect(err).ToNot(HaveOccurred()) | ||
| var oauthMetadata map[string]interface{} | ||
| g.Expect(json.Unmarshal([]byte(tt.cfg.Data[OauthMetadataConfigKey]), &oauthMetadata)).To(Succeed()) | ||
| g.Expect(oauthMetadata["issuer"]).To(Equal(tt.wantIssuer)) | ||
| g.Expect(oauthMetadata["authorization_endpoint"]).To(Equal(tt.wantAuthz)) | ||
| g.Expect(oauthMetadata["token_endpoint"]).To(Equal(tt.wantToken)) | ||
| }) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1115,7 +1115,7 @@ func (r *HostedClusterReconciler) reconcile(ctx context.Context, req ctrl.Reques | |
| } | ||
| } | ||
| if err == nil && serviceFirstNodePortAvailable(ignitionService) { | ||
| hcluster.Status.IgnitionEndpoint = fmt.Sprintf("%s:%d", serviceStrategy.NodePort.Address, ignitionService.Spec.Ports[0].NodePort) | ||
| hcluster.Status.IgnitionEndpoint = net.JoinHostPort(serviceStrategy.NodePort.Address, strconv.Itoa(int(ignitionService.Spec.Ports[0].NodePort))) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- hostedcluster_controller.go around line 1118 ---'
sed -n '1088,1135p' hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
echo
echo '--- reconcile_legacy.go around line 799 ---'
sed -n '770,825p' hypershift-operator/controllers/hostedcluster/reconcile_legacy.go
echo
echo '--- search tests for IgnitionEndpoint / IPv6 / NodePort Address ---'
rg -n "IgnitionEndpoint|NodePort.Address|JoinHostPort|IPv6|bracket" hypershift-operator/controllers/hostedcluster -g '*_test.go'Repository: openshift/hypershift Length of output: 10823 🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n "2001:|IPv6|JoinHostPort|IgnitionEndpoint|NodePort.Address" hypershift-operator/controllers/hostedcluster -g '*_test.go' -A 4 -B 4Repository: openshift/hypershift Length of output: 38286 🏁 Script executed: #!/bin/bash
set -euo pipefail
git ls-files hypershift-operator/controllers/hostedcluster/*_test.goRepository: openshift/hypershift Length of output: 894 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- NodePort-related tests in hostedcluster_controller_test.go ---'
rg -n "NodePort|ignition service|ignition proxy service|IgnitionEndpoint|JoinHostPort|Address" hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go -A 6 -B 6
echo
echo '--- Legacy reconcile test search in hostedcluster controller tests ---'
rg -n "legacy|reconcile_legacy|IgnitionEndpoint" hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go -A 3 -B 3Repository: openshift/hypershift Length of output: 28937 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- exact NodePort.Address usages in tests ---'
rg -n "NodePort\.Address|IgnitionEndpoint.*JoinHostPort|JoinHostPort\(serviceStrategy\.NodePort\.Address|serviceStrategy\.NodePort\.Address" hypershift-operator -g '*_test.go' -A 4 -B 4
echo
echo '--- any reconcile_legacy test file or legacy-path-specific test references ---'
rg -n "reconcile_legacy|legacy path|IgnitionEndpoint" hypershift-operator -g '*_test.go' -A 2 -B 2Repository: openshift/hypershift Length of output: 205 Add raw IPv6 NodePort coverage for both reconciler paths. The current tests don’t exercise
📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| } | ||
| default: | ||
| // We don't return the error here as reconciling won't solve the input problem. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
JoinHostPortalready conveys the intent — the comment could be dropped per project conventions (no comments on self-explanatory code).