api/middleware/cli_version.go
package middleware
import (
"fmt"
"net/http"
apierrors "code.cloudfoundry.org/korifi/api/errors"
"code.cloudfoundry.org/korifi/api/routing"
"github.com/Masterminds/semver"
"github.com/go-logr/logr"
"github.com/mileusna/useragent"
)
const minSupportedVersion = ">= 8.5.0-0"
func CFCliVersion(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := logr.FromContextOrDiscard(r.Context()).WithName("cf-cli-version-check")
userAgents := r.Header["User-Agent"]
if len(userAgents) == 0 {
next.ServeHTTP(w, r)
return
}
userAgent := useragent.Parse(userAgents[0])
if userAgent.Name != "cf" {
next.ServeHTTP(w, r)
return
}
cfCLIVersion, err := semver.NewVersion(userAgent.Version)
if err != nil {
routing.PresentError(logger, w, apierrors.NewInvalidRequestError(
err,
fmt.Sprintf("Failed to determine CF CLI version. Korifi requires CF CLI %s", minSupportedVersion),
))
return
}
if !versionConstraint(logger).Check(cfCLIVersion) {
routing.PresentError(logger, w, apierrors.NewInvalidRequestError(
err,
fmt.Sprintf("CF CLI version %s is not supported. Korifi requires CF CLI %s", cfCLIVersion, minSupportedVersion),
))
return
}
next.ServeHTTP(w, r)
})
}
func versionConstraint(logger logr.Logger) *semver.Constraints {
versionConstraint, err := semver.NewConstraint(minSupportedVersion)
if err != nil {
logger.Error(err, "failed to convert minSupportedVersion to version constraint", "minSupportedVersion", minSupportedVersion)
return &semver.Constraints{}
}
return versionConstraint
}