Skip to content

Commit

Permalink
Add security hub summary API (#18872)
Browse files Browse the repository at this point in the history
include WithCVE, WithArtifact option

Signed-off-by: stonezdj <daojunz@vmware.com>
  • Loading branch information
stonezdj authored Jul 12, 2023
1 parent 90259f3 commit 93e428d
Show file tree
Hide file tree
Showing 16 changed files with 1,101 additions and 1 deletion.
148 changes: 147 additions & 1 deletion api/v2.0/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6052,7 +6052,40 @@ paths:
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'

/security/summary:
get:
summary: Get vulnerability system summary
description: Retrieve the vulnerability summary of the system
tags:
- securityhub
operationId: getSecuritySummary
parameters:
- $ref: '#/parameters/requestId'
- name: with_dangerous_cve
in: query
description: Specify whether the dangerous CVE is include in the security summary
type: boolean
required: false
default: false
- name: with_dangerous_artifact
in: query
description: Specify whether the dangerous artifacts is include in the security summary
type: boolean
required: false
default: false
responses:
'200':
description: Success
schema:
$ref: '#/definitions/SecuritySummary'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
parameters:
query:
name: q
Expand Down Expand Up @@ -9614,3 +9647,116 @@ definitions:
type: boolean
description: if the scheduler is paused
x-omitempty: false
SecuritySummary:
type: object
description: the security summary
properties:
critical_cnt:
type: integer
format: int64
x-omitempty: false
description: the count of critical vulnerabilities
high_cnt:
type: integer
format: int64
description: the count of high vulnerabilities
medium_cnt:
type: integer
format: int64
x-omitempty: false
description: the count of medium vulnerabilities
low_cnt:
type: integer
format: int64
x-omitempty: false
description: the count of low vulnerabilities
none_cnt:
type: integer
format: int64
description: the count of none vulnerabilities
unknown_cnt:
type: integer
format: int64
description: the count of unknown vulnerabilities
total_vuls:
type: integer
format: int64
x-omitempty: false
description: the count of total vulnerabilities
scanned_cnt:
type: integer
format: int64
x-omitempty: false
description: the count of scanned artifacts
total_artifact:
type: integer
format: int64
x-omitempty: false
description: the total count of artifacts
fixable_cnt:
type: integer
format: int64
x-omitempty: false
description: the count of fixable vulnerabilities
dangerous_cves:
type: array
x-omitempty: true
description: the list of dangerous CVEs
items:
$ref: '#/definitions/DangerousCVE'
dangerous_artifacts:
type: array
x-omitempty: true
description: the list of dangerous artifacts
items:
$ref: '#/definitions/DangerousArtifact'
DangerousCVE:
type: object
description: the dangerous CVE information
properties:
cve_id:
type: string
description: the cve id
severity:
type: string
description: the severity of the CVE
cvss_score_v3:
type: number
format: float64
description: the cvss score v3
desc:
type: string
description: the description of the CVE
package:
type: string
description: the package of the CVE
version:
type: string
description: the version of the package
DangerousArtifact:
type: object
description: the dangerous artifact information
properties:
project_id:
type: integer
format: int64
description: the project id of the artifact
repository_name:
type: string
description: the repository name of the artifact
digest:
type: string
description: the digest of the artifact
critical_cnt:
type: integer
x-omitempty: false
description: the count of critical vulnerabilities
high_cnt:
type: integer
format: int64
x-omitempty: false
description: the count of high vulnerabilities
medium_cnt:
type: integer
x-omitempty: false
description: the count of medium vulnerabilities
1 change: 1 addition & 0 deletions src/common/rbac/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,5 @@ const (
ResourcePurgeAuditLog = Resource("purge-audit")
ResourceExportCVE = Resource("export-cve")
ResourceJobServiceMonitor = Resource("jobservice-monitor")
ResourceSecurityHub = Resource("security-hub")
)
2 changes: 2 additions & 0 deletions src/common/rbac/system/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@ var (
{Resource: rbac.ResourceJobServiceMonitor, Action: rbac.ActionRead},
{Resource: rbac.ResourceJobServiceMonitor, Action: rbac.ActionList},
{Resource: rbac.ResourceJobServiceMonitor, Action: rbac.ActionStop},

{Resource: rbac.ResourceSecurityHub, Action: rbac.ActionRead},
}
)
138 changes: 138 additions & 0 deletions src/controller/securityhub/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// 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 securityhub

import (
"context"

"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/pkg"
"github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/scan/scanner"
"github.com/goharbor/harbor/src/pkg/securityhub"
secHubModel "github.com/goharbor/harbor/src/pkg/securityhub/model"
)

// Ctl is the global controller for security hub
var Ctl = NewController()

// Options define the option to query summary info
type Options struct {
WithCVE bool
WithArtifact bool
}

// Option define the func to build options
type Option func(*Options)

func newOptions(options ...Option) *Options {
opts := &Options{}
for _, f := range options {
f(opts)
}
return opts
}

// WithCVE enable CVE info in summary
func WithCVE(enable bool) Option {
return func(o *Options) {
o.WithCVE = enable
}
}

// WithArtifact enable artifact info in summary
func WithArtifact(enable bool) Option {
return func(o *Options) {
o.WithArtifact = enable
}
}

// Controller controller of security hub
type Controller interface {
// SecuritySummary returns the security summary of the specified project.
SecuritySummary(ctx context.Context, projectID int64, options ...Option) (*secHubModel.Summary, error)
}

type controller struct {
artifactMgr artifact.Manager
scannerMgr scanner.Manager
secHubMgr securityhub.Manager
}

// NewController ...
func NewController() Controller {
return &controller{
artifactMgr: pkg.ArtifactMgr,
scannerMgr: scanner.New(),
secHubMgr: securityhub.Mgr,
}
}

func (c *controller) SecuritySummary(ctx context.Context, projectID int64, options ...Option) (*secHubModel.Summary, error) {
opts := newOptions(options...)
scannerUUID, err := c.defaultScannerUUID(ctx)
if err != nil {
return nil, err
}
sum, err := c.secHubMgr.Summary(ctx, scannerUUID, projectID, nil)
if err != nil {
return nil, err
}
sum.TotalArtifactCnt, err = c.totalArtifactCount(ctx, projectID)
if err != nil {
return nil, err
}
sum.ScannedCnt, err = c.secHubMgr.ScannedArtifactsCount(ctx, scannerUUID, projectID, nil)
if err != nil {
return nil, err
}
if opts.WithCVE {
sum.DangerousCVEs, err = c.secHubMgr.DangerousCVEs(ctx, scannerUUID, projectID, nil)
if err != nil {
return nil, err
}
}
if opts.WithArtifact {
sum.DangerousArtifacts, err = c.secHubMgr.DangerousArtifacts(ctx, scannerUUID, projectID, nil)
if err != nil {
return nil, err
}
}
return sum, nil
}

func (c *controller) scannedArtifactCount(ctx context.Context, projectID int64) (int64, error) {
scannerUUID, err := c.defaultScannerUUID(ctx)
if err != nil {
return 0, err
}
return c.secHubMgr.ScannedArtifactsCount(ctx, scannerUUID, projectID, nil)
}

func (c *controller) totalArtifactCount(ctx context.Context, projectID int64) (int64, error) {
if projectID == 0 {
return c.artifactMgr.Count(ctx, nil)
}
return c.artifactMgr.Count(ctx, q.New(q.KeyWords{"project_id": projectID}))
}

// defaultScannerUUID returns the default scanner uuid.
func (c *controller) defaultScannerUUID(ctx context.Context) (string, error) {
reg, err := c.scannerMgr.GetDefault(ctx)
if err != nil {
return "", err
}
return reg.UUID, nil
}
Loading

0 comments on commit 93e428d

Please sign in to comment.