feat(vuln-severity): map negligible to none to match CVSS v3 ratings (#9885)

BREAKING CHANGE: the value negligible of severity in project metadata will change to none in the responses of project APIs

Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
He Weiwei 2019-11-18 14:36:51 +08:00 committed by GitHub
parent 8b740ace8a
commit 0c068d81f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 31 deletions

View File

@ -4905,7 +4905,7 @@ definitions:
description: 'Whether prevent the vulnerable images from running. The valid values are "true", "false".' description: 'Whether prevent the vulnerable images from running. The valid values are "true", "false".'
severity: severity:
type: string type: string
description: 'If the vulnerability is high than severity defined here, the images can''t be pulled. The valid values are "negligible", "low", "medium", "high", "critical".' description: 'If the vulnerability is high than severity defined here, the images can''t be pulled. The valid values are "none", "low", "medium", "high", "critical".'
auto_scan: auto_scan:
type: string type: string
description: 'Whether scan images automatically when pushing. The valid values are "true", "false".' description: 'Whether scan images automatically when pushing. The valid values are "true", "false".'

View File

@ -26,11 +26,6 @@ const (
ProMetaSeverity = "severity" ProMetaSeverity = "severity"
ProMetaAutoScan = "auto_scan" ProMetaAutoScan = "auto_scan"
ProMetaReuseSysCVEWhitelist = "reuse_sys_cve_whitelist" ProMetaReuseSysCVEWhitelist = "reuse_sys_cve_whitelist"
SeverityNegligible = "negligible"
SeverityLow = "low"
SeverityMedium = "medium"
SeverityHigh = "high"
SeverityCritical = "critical"
) )
// ProjectMetadata holds the metadata of a project. // ProjectMetadata holds the metadata of a project.

View File

@ -15,18 +15,18 @@
package api package api
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"errors"
"github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/promgr/metamgr" "github.com/goharbor/harbor/src/core/promgr/metamgr"
"github.com/goharbor/harbor/src/pkg/scan/vuln"
) )
// MetadataAPI ... // MetadataAPI ...
@ -230,12 +230,12 @@ func validateProjectMetadata(metas map[string]string) (map[string]string, error)
value, exist := metas[models.ProMetaSeverity] value, exist := metas[models.ProMetaSeverity]
if exist { if exist {
switch strings.ToLower(value) { severity := vuln.ParseSeverityVersion3(strings.ToLower(value))
case models.SeverityHigh, models.SeverityMedium, models.SeverityLow, models.SeverityNegligible: if severity == vuln.Unknown {
metas[models.ProMetaSeverity] = strings.ToLower(value)
default:
return nil, fmt.Errorf("invalid severity %s", value) return nil, fmt.Errorf("invalid severity %s", value)
} }
metas[models.ProMetaSeverity] = strings.ToLower(severity.String())
} }
return metas, nil return metas, nil

View File

@ -19,6 +19,7 @@ import (
"net/http" "net/http"
"regexp" "regexp"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@ -32,6 +33,7 @@ import (
errutil "github.com/goharbor/harbor/src/common/utils/error" errutil "github.com/goharbor/harbor/src/common/utils/error"
"github.com/goharbor/harbor/src/common/utils/log" "github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/pkg/scan/vuln"
"github.com/goharbor/harbor/src/pkg/types" "github.com/goharbor/harbor/src/pkg/types"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -458,6 +460,11 @@ func (p *ProjectAPI) List() {
} }
func (p *ProjectAPI) populateProperties(project *models.Project) error { func (p *ProjectAPI) populateProperties(project *models.Project) error {
// Transform the severity to severity of CVSS v3.0 Ratings
if severity, ok := project.GetMetadata(models.ProMetaSeverity); ok {
project.SetMetadata(models.ProMetaSeverity, strings.ToLower(vuln.ParseSeverityVersion3(severity).String()))
}
if p.SecurityCtx.IsAuthenticated() { if p.SecurityCtx.IsAuthenticated() {
roles := p.SecurityCtx.GetProjectRoles(project.ProjectID) roles := p.SecurityCtx.GetProjectRoles(project.ProjectID)
project.RoleList = roles project.RoleList = roles

View File

@ -389,7 +389,7 @@ func (pc PmsPolicyChecker) VulnerablePolicy(name string) (bool, vuln.Severity, m
} }
} }
return project.VulPrevented(), getProjectVulnSeverity(project), wl return project.VulPrevented(), vuln.ParseSeverityVersion3(project.Severity()), wl
} }
// NewPMSPolicyChecker returns an instance of an pmsPolicyChecker // NewPMSPolicyChecker returns an instance of an pmsPolicyChecker
@ -607,20 +607,3 @@ func FireQuotaEvent(req *http.Request, level int, msg string) {
} }
}() }()
} }
func getProjectVulnSeverity(project *models.Project) vuln.Severity {
mp := map[string]vuln.Severity{
models.SeverityNegligible: vuln.Negligible,
models.SeverityLow: vuln.Low,
models.SeverityMedium: vuln.Medium,
models.SeverityHigh: vuln.High,
models.SeverityCritical: vuln.Critical,
}
severity, ok := mp[project.Severity()]
if !ok {
return vuln.Unknown
}
return severity
}

View File

@ -14,6 +14,10 @@
package vuln package vuln
import (
"strings"
)
const ( const (
// None - only used to mark the overall severity of the scanned artifacts, // None - only used to mark the overall severity of the scanned artifacts,
// means no vulnerabilities attached with the artifacts, // means no vulnerabilities attached with the artifacts,
@ -62,3 +66,23 @@ func (s Severity) Code() int {
return 99 return 99
} }
} }
func (s Severity) String() string {
return string(s)
}
// ParseSeverityVersion3 returns severity of CVSS v3.0 Ratings
func ParseSeverityVersion3(str string) Severity {
severity := Severity(strings.Title(str))
// There are `None`, `Low`, `Medium`, `High` and `Critical` severity rankings in CVSS v3.0 Ratings,
// so map `negligible` severity to `none`
switch severity {
case None, Low, Medium, High, Critical:
return severity
case Negligible:
return None
default:
return Unknown
}
}

View File

@ -0,0 +1,52 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package vuln
import (
"testing"
)
func TestParseSeverityVersion3(t *testing.T) {
type args struct {
str string
}
tests := []struct {
name string
args args
want Severity
}{
{"none", args{"none"}, None},
{"None", args{"None"}, None},
{"negligible", args{"negligible"}, None},
{"Negligible", args{"Negligible"}, None},
{"low", args{"low"}, Low},
{"Low", args{"Low"}, Low},
{"medium", args{"medium"}, Medium},
{"Medium", args{"Medium"}, Medium},
{"high", args{"high"}, High},
{"High", args{"High"}, High},
{"critical", args{"critical"}, Critical},
{"Critical", args{"Critical"}, Critical},
{"invalid", args{"invalid"}, Unknown},
{"Invalid", args{"Invalid"}, Unknown},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParseSeverityVersion3(tt.args.str); got != tt.want {
t.Errorf("ParseSeverityVersion3() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -74,7 +74,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
{severity: 'high', severityLevel: 'VULNERABILITY.SEVERITY.HIGH'}, {severity: 'high', severityLevel: 'VULNERABILITY.SEVERITY.HIGH'},
{severity: 'medium', severityLevel: 'VULNERABILITY.SEVERITY.MEDIUM'}, {severity: 'medium', severityLevel: 'VULNERABILITY.SEVERITY.MEDIUM'},
{severity: 'low', severityLevel: 'VULNERABILITY.SEVERITY.LOW'}, {severity: 'low', severityLevel: 'VULNERABILITY.SEVERITY.LOW'},
{severity: 'negligible', severityLevel: 'VULNERABILITY.SEVERITY.NEGLIGIBLE'}, {severity: 'none', severityLevel: 'VULNERABILITY.SEVERITY.NONE'},
]; ];
userSystemWhitelist: boolean = true; userSystemWhitelist: boolean = true;
showAddModal: boolean = false; showAddModal: boolean = false;