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".'
severity:
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:
type: string
description: 'Whether scan images automatically when pushing. The valid values are "true", "false".'

View File

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

View File

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

View File

@ -19,6 +19,7 @@ import (
"net/http"
"regexp"
"strconv"
"strings"
"sync"
"time"
@ -32,6 +33,7 @@ import (
errutil "github.com/goharbor/harbor/src/common/utils/error"
"github.com/goharbor/harbor/src/common/utils/log"
"github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/pkg/scan/vuln"
"github.com/goharbor/harbor/src/pkg/types"
"github.com/pkg/errors"
)
@ -458,6 +460,11 @@ func (p *ProjectAPI) List() {
}
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() {
roles := p.SecurityCtx.GetProjectRoles(project.ProjectID)
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
@ -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
import (
"strings"
)
const (
// None - only used to mark the overall severity of the scanned artifacts,
// means no vulnerabilities attached with the artifacts,
@ -62,3 +66,23 @@ func (s Severity) Code() int {
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: 'medium', severityLevel: 'VULNERABILITY.SEVERITY.MEDIUM'},
{severity: 'low', severityLevel: 'VULNERABILITY.SEVERITY.LOW'},
{severity: 'negligible', severityLevel: 'VULNERABILITY.SEVERITY.NEGLIGIBLE'},
{severity: 'none', severityLevel: 'VULNERABILITY.SEVERITY.NONE'},
];
userSystemWhitelist: boolean = true;
showAddModal: boolean = false;