diff --git a/API/harbor/swagger.yaml b/API/harbor/swagger.yaml index 99b318f4c..f0f8ecc13 100644 --- a/API/harbor/swagger.yaml +++ b/API/harbor/swagger.yaml @@ -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".' diff --git a/src/common/models/pro_meta.go b/src/common/models/pro_meta.go index d733e05de..9c8565747 100644 --- a/src/common/models/pro_meta.go +++ b/src/common/models/pro_meta.go @@ -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. diff --git a/src/core/api/metadata.go b/src/core/api/metadata.go index 12fe9ac22..490e5be74 100644 --- a/src/core/api/metadata.go +++ b/src/core/api/metadata.go @@ -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 diff --git a/src/core/api/project.go b/src/core/api/project.go index c5f1eb0bc..c24f07492 100644 --- a/src/core/api/project.go +++ b/src/core/api/project.go @@ -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 diff --git a/src/core/middlewares/util/util.go b/src/core/middlewares/util/util.go index 1726f8ea6..80ccacb7e 100644 --- a/src/core/middlewares/util/util.go +++ b/src/core/middlewares/util/util.go @@ -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 -} diff --git a/src/pkg/scan/vuln/severity.go b/src/pkg/scan/vuln/severity.go index c6fd209ea..eaa2b1b3e 100644 --- a/src/pkg/scan/vuln/severity.go +++ b/src/pkg/scan/vuln/severity.go @@ -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 + } +} diff --git a/src/pkg/scan/vuln/severity_test.go b/src/pkg/scan/vuln/severity_test.go new file mode 100644 index 000000000..cd77ca95e --- /dev/null +++ b/src/pkg/scan/vuln/severity_test.go @@ -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) + } + }) + } +} diff --git a/src/portal/lib/src/project-policy-config/project-policy-config.component.ts b/src/portal/lib/src/project-policy-config/project-policy-config.component.ts index 2d4f26fe3..466294011 100644 --- a/src/portal/lib/src/project-policy-config/project-policy-config.component.ts +++ b/src/portal/lib/src/project-policy-config/project-policy-config.component.ts @@ -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;