Skip to content

Commit

Permalink
OCPBUGS-33378: Verify Build Webhooks on Upgrade
Browse files Browse the repository at this point in the history
Updating the build suite test to verify the unautenticated build
webhook behavior on upgrade. For clusters upgrading from v4.15 or
earlier to v4.16, unauthenticated webhooks should continue to be
allowed. For clusters that upgrade from v4.16 to a later version,
unauthenticated webhooks should be denied by default.

Signed-off-by: Adam Kaplan <adam.kaplan@redhat.com>
  • Loading branch information
adambkaplan committed May 8, 2024
1 parent d5836ab commit cdcc3ef
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 2 deletions.
2 changes: 2 additions & 0 deletions pkg/clusterversion/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package clusterversion contains utitlities to access version information for the cluster.
package clusterversion
45 changes: 45 additions & 0 deletions pkg/clusterversion/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package clusterversion

import (
"strings"

"golang.org/x/mod/semver"

configv1 "github.com/openshift/api/config/v1"
)

// IsUpgradedFromMinorVersion returns true if the cluster has been upgraded from or through the given version.
// This will only check for X.Y version upgrades - it will ignore patch/z-stream versions.
// Returns false if the input version is not a semver.
func IsUpgradedFromMinorVersion(version string, cv *configv1.ClusterVersion) bool {
fromMajorMinor := majorMinorVersion(version)
if !semver.IsValid(fromMajorMinor) {
return false
}

beforeOrAtVersionFound := false
atOrLaterVersionFound := false

// History is always ordered from most recent to oldest.
for _, history := range cv.Status.History {
historyMajorMinor := majorMinorVersion(history.Version)
// Version in history can be empty or not a semver. Skip in this case.
if !semver.IsValid(historyMajorMinor) {
continue
}
if semver.Compare(historyMajorMinor, fromMajorMinor) >= 0 {
atOrLaterVersionFound = true
}
if semver.Compare(historyMajorMinor, fromMajorMinor) <= 0 {
beforeOrAtVersionFound = true
}
}
return beforeOrAtVersionFound && atOrLaterVersionFound
}

func majorMinorVersion(version string) string {
if !strings.HasPrefix(version, "v") {
version = "v" + version
}
return semver.MajorMinor(version)
}
71 changes: 71 additions & 0 deletions pkg/clusterversion/upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package clusterversion

import (
"testing"

configv1 "github.com/openshift/api/config/v1"
)

func TestIsUpgradedFromMinorVersion(t *testing.T) {
cases := []struct {
Name string
UpgradeFromVersion string
VersionHistory []string
Expected bool
}{
{
Name: "no history",
UpgradeFromVersion: "4.15",
Expected: false,
},
{
Name: "upgraded to 4.16 from 4.15",
UpgradeFromVersion: "4.15",
VersionHistory: []string{"4.16.0", "4.15.9", "4.15.7", "4.15.2"},
Expected: true,
},
{
Name: "upgraded to 4.16 from 4.14",
UpgradeFromVersion: "4.15",
VersionHistory: []string{"4.16.0", "4.15.9", "4.15.7", "4.15.2", "4.14.9"},
Expected: true,
},
{
Name: "skip odd minor version",
UpgradeFromVersion: "4.15",
VersionHistory: []string{"4.16.0", "4.14.9", "4.14.2", "4.12.14", "4.12.8"},
Expected: true,
},
{
Name: "not reached upgrade",
UpgradeFromVersion: "4.15",
VersionHistory: []string{"4.14.0", "4.13.9", "4.13.2", "4.12.14", "4.12.8"},
Expected: false,
},
{
Name: "invalid version",
UpgradeFromVersion: "bad-data",
VersionHistory: []string{"4.16.0", "4.15.9", "4.15.7"},
Expected: false,
},
}
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
history := []configv1.UpdateHistory{}
for _, version := range tc.VersionHistory {
history = append(history, configv1.UpdateHistory{
Version: version,
})
}
cv := &configv1.ClusterVersion{
Status: configv1.ClusterVersionStatus{
History: history,
},
}
upgraded := IsUpgradedFromMinorVersion(tc.UpgradeFromVersion, cv)
if upgraded != tc.Expected {
t.Errorf("expected %v, got %v", tc.Expected, upgraded)
}
})
}
}
22 changes: 20 additions & 2 deletions test/extended/builds/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
admissionapi "k8s.io/pod-security-admission/api"

buildv1 "github.com/openshift/api/build/v1"
configv1 "github.com/openshift/api/config/v1"
imagev1 "github.com/openshift/api/image/v1"

"github.com/openshift/origin/pkg/clusterversion"
exutil "github.com/openshift/origin/test/extended/util"
)

Expand All @@ -47,12 +49,15 @@ var _ = g.Describe("[sig-builds][Feature:Builds][webhook]", func() {
})

func TestWebhook(t g.GinkgoTInterface, oc *exutil.CLI) {
ctx := context.Background()
clusterAdminBuildClient := oc.AdminBuildClient().BuildV1()
clusterVersion, err := oc.AdminConfigClient().ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{})
o.Expect(err).NotTo(o.HaveOccurred(), "get cluster version")
adminHTTPClient := clusterAdminBuildClient.RESTClient().(*rest.RESTClient).Client

// create buildconfig
buildConfig := mockBuildConfigImageParms("originalimage", "imagestream", "validtag")
if _, err := clusterAdminBuildClient.BuildConfigs(oc.Namespace()).Create(context.Background(), buildConfig, metav1.CreateOptions{}); err != nil {
if _, err := clusterAdminBuildClient.BuildConfigs(oc.Namespace()).Create(ctx, buildConfig, metav1.CreateOptions{}); err != nil {
t.Fatalf("Unexpected error: %v", err)
}

Expand Down Expand Up @@ -125,7 +130,7 @@ func TestWebhook(t g.GinkgoTInterface, oc *exutil.CLI) {
},
},
},
expectedStatus: http.StatusForbidden,
expectedStatus: expectedUnauthWebhookStatus(clusterVersion),
},
}

Expand Down Expand Up @@ -159,6 +164,19 @@ func TestWebhook(t g.GinkgoTInterface, oc *exutil.CLI) {
}
}

// expectedUnauthWebhookStatus returns the exepcted HTTPS status code for unauthenticated webhook
// requests sent to a stock/unmodified OpenShift cluster.
//
// For clusters upgraded from or through 4.15, unauthenticated webhooks are allowed and should
// return code 200 (OK). Starting in OCP 4.16, unauthenticated webhooks should return code 403
// (Forbidden).
func expectedUnauthWebhookStatus(cv *configv1.ClusterVersion) int {
if clusterversion.IsUpgradedFromMinorVersion("4.15", cv) {
return http.StatusOK
}
return http.StatusForbidden
}

func TestWebhookGitHubPushWithImage(t g.GinkgoTInterface, oc *exutil.CLI) {
const registryHostname = "registry:3000"

Expand Down

0 comments on commit cdcc3ef

Please sign in to comment.