Skip to content

Commit

Permalink
Implemented validation logic for the webhook
Browse files Browse the repository at this point in the history
- Created a single Validate() function to validate both updating and creating Jenkins CR.
- Implemented the Validate function to fetch warnings from the API and do security check if
  being enabled.
  • Loading branch information
sharmapulkit04 committed Jul 11, 2021
1 parent e87c7ca commit 8f4a92e
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 5 deletions.
137 changes: 132 additions & 5 deletions api/v1alpha2/jenkins_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ limitations under the License.
package v1alpha2

import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"time"

"github.com/jenkinsci/kubernetes-operator/pkg/plugins"
"golang.org/x/mod/semver"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -41,21 +49,140 @@ var _ webhook.Validator = &Jenkins{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (in *Jenkins) ValidateCreate() error {
jenkinslog.Info("validate create", "name", in.Name)
if in.Spec.ValidateSecurityWarnings {
jenkinslog.Info("validate create", "name", in.Name)
return Validate(*in)
}

// TODO(user): fill in your validation logic upon object creation.
return nil
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (in *Jenkins) ValidateUpdate(old runtime.Object) error {
jenkinslog.Info("validate update", "name", in.Name)
if in.Spec.ValidateSecurityWarnings {
jenkinslog.Info("validate update", "name", in.Name)
return Validate(*in)
}

// TODO(user): fill in your validation logic upon object update.
return nil
}

func (in *Jenkins) ValidateDelete() error {
// TODO(user): fill in your validation logic upon object deletion.
return nil
}

type Warnings struct {
Warnings []Warning `json:"securityWarnings"`
}

type Warning struct {
Versions []Version `json:"versions"`
ID string `json:"id"`
Message string `json:"message"`
URL string `json:"url"`
Active bool `json:"active"`
}
type Version struct {
FirstVersion string `json:"firstVersion"`
LastVersion string `json:"lastVersion"`
}

const APIURL string = "https://plugins.jenkins.io/api/plugin/"

func MakeSemanticVersion(version string) string {
version = "v" + version
return semver.Canonical(version)
}

func CompareVersions(firstVersion string, lastVersion string, pluginVersion string) bool {
firstSemVer := MakeSemanticVersion(firstVersion)
lastSemVer := MakeSemanticVersion(lastVersion)
pluginSemVer := MakeSemanticVersion(pluginVersion)
if semver.Compare(pluginSemVer, firstSemVer) == -1 || semver.Compare(pluginSemVer, lastSemVer) == 1 {
return false
}
return true
}

func CheckSecurityWarnings(pluginName string, pluginVersion string) (bool, error) {
jenkinslog.Info("checking security warnings", "plugin: ", pluginName)
pluginURL := APIURL + pluginName
client := &http.Client{
Timeout: time.Second * 30,
}
request, err := http.NewRequest("GET", pluginURL, nil)
if err != nil {
return false, err
}
request.Header.Add("Accept", "application/json")
request.Header.Add("Content-Type", "application/json")
response, err := client.Do(request)
if err != nil {
return false, err
}
defer response.Body.Close()
bodyBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return false, err
}
securityWarnings := Warnings{}

jsonErr := json.Unmarshal(bodyBytes, &securityWarnings)
if jsonErr != nil {
return false, err
}

jenkinslog.Info("Validate()", "warnings", securityWarnings)

for _, warning := range securityWarnings.Warnings {
for _, version := range warning.Versions {
firstVersion := version.FirstVersion
lastVersion := version.LastVersion
if len(firstVersion) == 0 {
firstVersion = "0" // setting default value in case of empty string
}
if len(lastVersion) == 0 {
lastVersion = pluginVersion // setting default value in case of empty string
}

if CompareVersions(firstVersion, lastVersion, pluginVersion) {
jenkinslog.Info("security Vulnerabilities detected", "message", warning.Message, "Check security Advisory", warning.URL)
return true, nil
}
}
}

return false, nil
}

func Validate(r Jenkins) error {
basePlugins := plugins.BasePlugins()

for _, plugin := range basePlugins {
name := plugin.Name
version := plugin.Version
hasWarnings, err := CheckSecurityWarnings(name, version)
if err != nil {
return err
}
if hasWarnings {
errormsg := "Security Vulnerabilities detected in base plugin:" + name
return errors.New(errormsg)
}
}

for _, plugin := range r.Spec.Master.Plugins {
name := plugin.Name
version := plugin.Version
hasWarnings, err := CheckSecurityWarnings(name, version)
if err != nil {
return err
}
if hasWarnings {
errormsg := "Security Vulnerabilities detected in the user defined plugin: " + name
return errors.New(errormsg)
}
}

return nil
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ require (
k8s.io/client-go v0.20.2
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
sigs.k8s.io/controller-runtime v0.7.0
golang.org/x/mod v0.4.2

)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down

0 comments on commit 8f4a92e

Please sign in to comment.