Code optimization and cleanup
This commit is contained in:
parent
f527a8c5cb
commit
9594c8e7cd
|
|
@ -27,12 +27,10 @@ import (
|
|||
"time"
|
||||
|
||||
//"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/plugins"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
|
@ -41,10 +39,12 @@ import (
|
|||
|
||||
var (
|
||||
jenkinslog = logf.Log.WithName("jenkins-resource") // log is for logging in this package.
|
||||
PluginsMgr PluginDataManager = *NewPluginsDataManager("https://ci.jenkins.io/job/Infra/job/plugin-site-api/job/generate-data/lastSuccessfulBuild/artifact/plugins.json.gzip", "/tmp/plugins.json.gzip", "/tmp/plugins.json", false, time.Duration(1000)*time.Second)
|
||||
PluginsMgr PluginDataManager = *NewPluginsDataManager("/tmp/plugins.json.gzip", "/tmp/plugins.json", false, time.Duration(1000)*time.Second)
|
||||
_ webhook.Validator = &Jenkins{}
|
||||
)
|
||||
|
||||
const Hosturl = "https://ci.jenkins.io/job/Infra/job/plugin-site-api/job/generate-data/lastSuccessfulBuild/artifact/plugins.json.gzip"
|
||||
|
||||
func (in *Jenkins) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(in).
|
||||
|
|
@ -82,13 +82,12 @@ func (in *Jenkins) ValidateDelete() error {
|
|||
|
||||
type PluginDataManager struct {
|
||||
PluginDataCache PluginsInfo
|
||||
Hosturl string
|
||||
Timeout time.Duration
|
||||
CompressedFilePath string
|
||||
PluginDataFile string
|
||||
IsCached bool
|
||||
Attempts int
|
||||
SleepTime int
|
||||
SleepTime time.Duration
|
||||
}
|
||||
|
||||
type PluginsInfo struct {
|
||||
|
|
@ -155,7 +154,7 @@ func Validate(r Jenkins) error {
|
|||
if len(lastVersion) == 0 {
|
||||
lastVersion = pluginData.Version // setting default value in case of empty string
|
||||
}
|
||||
|
||||
// checking if this warning applies to our version as well
|
||||
if compareVersions(firstVersion, lastVersion, pluginData.Version) {
|
||||
jenkinslog.Info("Security Vulnerability detected in "+pluginData.Kind+" "+plugin.Name+":"+pluginData.Version, "Warning message", warning.Message, "For more details,check security advisory", warning.URL)
|
||||
hasVulnerabilities = true
|
||||
|
|
@ -186,9 +185,8 @@ func Validate(r Jenkins) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewPluginsDataManager(hosturl string, compressedFilePath string, pluginDataFile string, isCached bool, timeout time.Duration) *PluginDataManager {
|
||||
func NewPluginsDataManager(compressedFilePath string, pluginDataFile string, isCached bool, timeout time.Duration) *PluginDataManager {
|
||||
return &PluginDataManager{
|
||||
Hosturl: hosturl,
|
||||
CompressedFilePath: compressedFilePath,
|
||||
PluginDataFile: pluginDataFile,
|
||||
IsCached: isCached,
|
||||
|
|
@ -196,63 +194,72 @@ func NewPluginsDataManager(hosturl string, compressedFilePath string, pluginData
|
|||
}
|
||||
}
|
||||
|
||||
// Downloads extracts and reads the JSON data in every 12 hours
|
||||
func (in *PluginDataManager) FetchPluginData(isInitialized chan bool) {
|
||||
func (in *PluginDataManager) ManagePluginData(sig chan bool) {
|
||||
var isInit bool // checks if the operator
|
||||
var retryInterval time.Duration
|
||||
for {
|
||||
jenkinslog.Info("Initializing/Updating the plugin data cache")
|
||||
var isDownloaded, isExtracted, isCached bool
|
||||
var err error
|
||||
for in.Attempts = 0; in.Attempts < 5; in.Attempts++ {
|
||||
err = in.download()
|
||||
if err == nil {
|
||||
isDownloaded = true
|
||||
break
|
||||
}
|
||||
isCached := in.fetchPluginData()
|
||||
if !isInit {
|
||||
sig <- isCached // sending signal to main to continue
|
||||
isInit = false
|
||||
}
|
||||
|
||||
if isDownloaded {
|
||||
for in.Attempts = 0; in.Attempts < 5; in.Attempts++ {
|
||||
err = in.extract()
|
||||
if err == nil {
|
||||
isExtracted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
in.IsCached = in.IsCached || isCached
|
||||
if !isCached {
|
||||
retryInterval = time.Duration(1) * time.Hour
|
||||
} else {
|
||||
jenkinslog.Info("Cache Plugin Data", "failed to download file", err)
|
||||
retryInterval = time.Duration(12) * time.Hour
|
||||
}
|
||||
|
||||
if isExtracted {
|
||||
for in.Attempts = 0; in.Attempts < 5; in.Attempts++ {
|
||||
err = in.cache()
|
||||
if err == nil {
|
||||
isCached = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !isCached {
|
||||
jenkinslog.Info("Cache Plugin Data", "failed to read plugin data file", err)
|
||||
}
|
||||
} else {
|
||||
jenkinslog.Info("Cache Plugin Data", "failed to extract file", err)
|
||||
}
|
||||
|
||||
// Checks for the first time
|
||||
if !in.IsCached {
|
||||
isInitialized <- isCached
|
||||
in.IsCached = isCached
|
||||
}
|
||||
|
||||
if isCached {
|
||||
in.SleepTime = 12
|
||||
} else {
|
||||
in.SleepTime = 1
|
||||
}
|
||||
time.Sleep(time.Duration(in.SleepTime) * time.Hour)
|
||||
time.Sleep(retryInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// Downloads extracts and reads the JSON data in every 12 hours
|
||||
func (in *PluginDataManager) fetchPluginData() bool {
|
||||
jenkinslog.Info("Initializing/Updating the plugin data cache")
|
||||
var err error
|
||||
for in.Attempts = 0; in.Attempts < 5; in.Attempts++ {
|
||||
err = in.download()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
jenkinslog.V(1).Info("Cache Plugin Data", "failed to download file", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
jenkinslog.Info("Cache Plugin Data", "failed to download file", err)
|
||||
return false
|
||||
}
|
||||
|
||||
for in.Attempts = 0; in.Attempts < 5; in.Attempts++ {
|
||||
err = in.extract()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
jenkinslog.V(1).Info("Cache Plugin Data", "failed to extract file", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
jenkinslog.Info("Cache Plugin Data", "failed to extract file", err)
|
||||
return false
|
||||
}
|
||||
|
||||
for in.Attempts = 0; in.Attempts < 5; in.Attempts++ {
|
||||
err = in.cache()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
jenkinslog.V(1).Info("Cache Plugin Data", "failed to read plugin data file", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
jenkinslog.Info("Cache Plugin Data", "failed to read plugin data file", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (in *PluginDataManager) download() error {
|
||||
out, err := os.Create(in.CompressedFilePath)
|
||||
if err != nil {
|
||||
|
|
@ -264,11 +271,12 @@ func (in *PluginDataManager) download() error {
|
|||
Timeout: in.Timeout,
|
||||
}
|
||||
|
||||
resp, err := client.Get(in.Hosturl)
|
||||
resp, err := client.Get(Hosturl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -307,7 +315,6 @@ func (in *PluginDataManager) cache() error {
|
|||
return err
|
||||
}
|
||||
defer jsonFile.Close()
|
||||
|
||||
byteValue, err := ioutil.ReadAll(jsonFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -337,47 +344,3 @@ func compareVersions(firstVersion string, lastVersion string, pluginVersion stri
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func CreateJenkinsCR(name string, namespace string, userPlugins []Plugin, validateSecurityWarnings bool) *Jenkins {
|
||||
jenkins := &Jenkins{
|
||||
TypeMeta: JenkinsTypeMeta(),
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: JenkinsSpec{
|
||||
GroovyScripts: GroovyScripts{
|
||||
Customization: Customization{
|
||||
Configurations: []ConfigMapRef{},
|
||||
Secret: SecretRef{
|
||||
Name: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
ConfigurationAsCode: ConfigurationAsCode{
|
||||
Customization: Customization{
|
||||
Configurations: []ConfigMapRef{},
|
||||
Secret: SecretRef{
|
||||
Name: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Master: JenkinsMaster{
|
||||
Plugins: userPlugins,
|
||||
DisableCSRFProtection: false,
|
||||
},
|
||||
ValidateSecurityWarnings: validateSecurityWarnings,
|
||||
Service: Service{
|
||||
Type: corev1.ServiceTypeNodePort,
|
||||
Port: constants.DefaultHTTPPortInt32,
|
||||
},
|
||||
JenkinsAPISettings: JenkinsAPISettings{AuthorizationStrategy: CreateUserAuthorizationStrategy},
|
||||
},
|
||||
}
|
||||
|
||||
return jenkins
|
||||
}
|
||||
|
||||
func CreateSecurityWarnings(firstVersion string, lastVersion string) []Warning {
|
||||
return []Warning{{Versions: []Version{{FirstVersion: firstVersion, LastVersion: lastVersion}}, ID: "null", Message: "unit testing", URL: "null", Active: false}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestMakeSemanticVersion(t *testing.T) {
|
||||
|
|
@ -77,7 +78,7 @@ func TestCompareVersions(t *testing.T) {
|
|||
func TestValidate(t *testing.T) {
|
||||
t.Run("Validating when plugins data file is not fetched", func(t *testing.T) {
|
||||
userplugins := []Plugin{{Name: "script-security", Version: "1.77"}, {Name: "git-client", Version: "3.9"}, {Name: "git", Version: "4.8.1"}, {Name: "plain-credentials", Version: "1.7"}}
|
||||
jenkinscr := *CreateJenkinsCR("Jenkins", "test", userplugins, true)
|
||||
jenkinscr := *createJenkinsCR(userplugins, true)
|
||||
got := jenkinscr.ValidateCreate()
|
||||
assert.Equal(t, got, errors.New("plugins data has not been fetched"))
|
||||
})
|
||||
|
|
@ -88,66 +89,89 @@ func TestValidate(t *testing.T) {
|
|||
{Name: "security-script"},
|
||||
{Name: "git-client"},
|
||||
{Name: "git"},
|
||||
{Name: "google-login", SecurityWarnings: CreateSecurityWarnings("", "1.2")},
|
||||
{Name: "sample-plugin", SecurityWarnings: CreateSecurityWarnings("", "0.8")},
|
||||
{Name: "google-login", SecurityWarnings: createSecurityWarnings("", "1.2")},
|
||||
{Name: "sample-plugin", SecurityWarnings: createSecurityWarnings("", "0.8")},
|
||||
{Name: "mailer"},
|
||||
{Name: "plain-credentials"}}}
|
||||
userplugins := []Plugin{{Name: "script-security", Version: "1.77"}, {Name: "git-client", Version: "3.9"}, {Name: "git", Version: "4.8.1"}, {Name: "plain-credentials", Version: "1.7"}}
|
||||
jenkinscr := *CreateJenkinsCR("Jenkins", "test", userplugins, true)
|
||||
jenkinscr := *createJenkinsCR(userplugins, true)
|
||||
got := jenkinscr.ValidateCreate()
|
||||
assert.Nil(t, got)
|
||||
})
|
||||
|
||||
t.Run("Validating a Jenkins CR with some of the plugins having security warnings and validation is turned on", func(t *testing.T) {
|
||||
PluginsMgr.PluginDataCache = PluginsInfo{Plugins: []PluginInfo{
|
||||
{Name: "security-script", SecurityWarnings: CreateSecurityWarnings("1.2", "2.2")},
|
||||
{Name: "workflow-cps", SecurityWarnings: CreateSecurityWarnings("2.59", "")},
|
||||
{Name: "security-script", SecurityWarnings: createSecurityWarnings("1.2", "2.2")},
|
||||
{Name: "workflow-cps", SecurityWarnings: createSecurityWarnings("2.59", "")},
|
||||
{Name: "git-client"},
|
||||
{Name: "git"},
|
||||
{Name: "sample-plugin", SecurityWarnings: CreateSecurityWarnings("0.8", "")},
|
||||
{Name: "command-launcher", SecurityWarnings: CreateSecurityWarnings("1.2", "1.4")},
|
||||
{Name: "sample-plugin", SecurityWarnings: createSecurityWarnings("0.8", "")},
|
||||
{Name: "command-launcher", SecurityWarnings: createSecurityWarnings("1.2", "1.4")},
|
||||
{Name: "plain-credentials"},
|
||||
{Name: "google-login", SecurityWarnings: CreateSecurityWarnings("1.1", "1.3")},
|
||||
{Name: "mailer", SecurityWarnings: CreateSecurityWarnings("1.0.3", "1.1.4")},
|
||||
{Name: "google-login", SecurityWarnings: createSecurityWarnings("1.1", "1.3")},
|
||||
{Name: "mailer", SecurityWarnings: createSecurityWarnings("1.0.3", "1.1.4")},
|
||||
}}
|
||||
userplugins := []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}}
|
||||
jenkinscr := *CreateJenkinsCR("Jenkins", "test", userplugins, true)
|
||||
jenkinscr := *createJenkinsCR(userplugins, true)
|
||||
got := jenkinscr.ValidateCreate()
|
||||
assert.Equal(t, got, errors.New("security vulnerabilities detected in the following user-defined plugins: \nworkflow-cps:2.59\ngoogle-login:1.2\nmailer:1.1"))
|
||||
})
|
||||
|
||||
t.Run("Updating a Jenkins CR with some of the plugins having security warnings and validation is turned on", func(t *testing.T) {
|
||||
PluginsMgr.PluginDataCache = PluginsInfo{Plugins: []PluginInfo{
|
||||
{Name: "handy-uri-templates-2-api", SecurityWarnings: CreateSecurityWarnings("2.1.8-1.0", "2.2.8-1.0")},
|
||||
{Name: "workflow-cps", SecurityWarnings: CreateSecurityWarnings("2.59", "")},
|
||||
{Name: "resource-disposer", SecurityWarnings: CreateSecurityWarnings("0.7", "1.2")},
|
||||
{Name: "handy-uri-templates-2-api", SecurityWarnings: createSecurityWarnings("2.1.8-1.0", "2.2.8-1.0")},
|
||||
{Name: "workflow-cps", SecurityWarnings: createSecurityWarnings("2.59", "")},
|
||||
{Name: "resource-disposer", SecurityWarnings: createSecurityWarnings("0.7", "1.2")},
|
||||
{Name: "git"},
|
||||
{Name: "jjwt-api"},
|
||||
{Name: "blueocean-github-pipeline", SecurityWarnings: CreateSecurityWarnings("1.2.0-alpha-2", "1.2.0-beta-5")},
|
||||
{Name: "command-launcher", SecurityWarnings: CreateSecurityWarnings("1.2", "1.4")},
|
||||
{Name: "blueocean-github-pipeline", SecurityWarnings: createSecurityWarnings("1.2.0-alpha-2", "1.2.0-beta-5")},
|
||||
{Name: "command-launcher", SecurityWarnings: createSecurityWarnings("1.2", "1.4")},
|
||||
{Name: "plain-credentials"},
|
||||
{Name: "ghprb", SecurityWarnings: CreateSecurityWarnings("1.1", "1.43")},
|
||||
{Name: "mailer", SecurityWarnings: CreateSecurityWarnings("1.0.3", "1.1.4")},
|
||||
{Name: "ghprb", SecurityWarnings: createSecurityWarnings("1.1", "1.43")},
|
||||
{Name: "mailer", SecurityWarnings: createSecurityWarnings("1.0.3", "1.1.4")},
|
||||
}}
|
||||
|
||||
userplugins := []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}}
|
||||
oldjenkinscr := *CreateJenkinsCR("Jenkins", "test", userplugins, true)
|
||||
oldjenkinscr := *createJenkinsCR(userplugins, true)
|
||||
|
||||
userplugins = []Plugin{{Name: "handy-uri-templates-2-api", Version: "2.1.8-1.0"}, {Name: "resource-disposer", Version: "0.8"}, {Name: "jjwt-api", Version: "0.11.2-9.c8b45b8bb173"}, {Name: "blueocean-github-pipeline", Version: "1.2.0-beta-3"}, {Name: "ghprb", Version: "1.39"}}
|
||||
newjenkinscr := *CreateJenkinsCR("Jenkins", "test", userplugins, true)
|
||||
newjenkinscr := *createJenkinsCR(userplugins, true)
|
||||
got := newjenkinscr.ValidateUpdate(&oldjenkinscr)
|
||||
assert.Equal(t, got, errors.New("security vulnerabilities detected in the following user-defined plugins: \nhandy-uri-templates-2-api:2.1.8-1.0\nresource-disposer:0.8\nblueocean-github-pipeline:1.2.0-beta-3\nghprb:1.39"))
|
||||
})
|
||||
|
||||
t.Run("Validation is turned off", func(t *testing.T) {
|
||||
userplugins := []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}}
|
||||
jenkinscr := *CreateJenkinsCR("Jenkins", "test", userplugins, false)
|
||||
jenkinscr := *createJenkinsCR(userplugins, false)
|
||||
got := jenkinscr.ValidateCreate()
|
||||
assert.Nil(t, got)
|
||||
|
||||
userplugins = []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}}
|
||||
newjenkinscr := *CreateJenkinsCR("jenkins", "test", userplugins, false)
|
||||
newjenkinscr := *createJenkinsCR(userplugins, false)
|
||||
got = newjenkinscr.ValidateUpdate(&jenkinscr)
|
||||
assert.Nil(t, got)
|
||||
})
|
||||
}
|
||||
|
||||
func createJenkinsCR(userPlugins []Plugin, validateSecurityWarnings bool) *Jenkins {
|
||||
jenkins := &Jenkins{
|
||||
TypeMeta: JenkinsTypeMeta(),
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "jenkins",
|
||||
Namespace: "test",
|
||||
},
|
||||
Spec: JenkinsSpec{
|
||||
Master: JenkinsMaster{
|
||||
Plugins: userPlugins,
|
||||
DisableCSRFProtection: false,
|
||||
},
|
||||
ValidateSecurityWarnings: validateSecurityWarnings,
|
||||
},
|
||||
}
|
||||
|
||||
return jenkins
|
||||
}
|
||||
|
||||
func createSecurityWarnings(firstVersion string, lastVersion string) []Warning {
|
||||
return []Warning{{Versions: []Version{{FirstVersion: firstVersion, LastVersion: lastVersion}}, ID: "null", Message: "unit testing", URL: "null", Active: false}}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue