API for system CVE allowlist to new model (#14412)

Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
Daniel Jiang 2021-03-12 10:23:48 +08:00 committed by GitHub
parent 4ef93565f3
commit 0d4992a41e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 685 additions and 597 deletions

View File

@ -2739,6 +2739,44 @@ paths:
$ref: '#/responses/403'
'500':
$ref: '#/responses/500'
/system/CVEAllowlist:
get:
summary: Get the system level allowlist of CVE.
description: Get the system level allowlist of CVE. This API can be called by all authenticated users.
operationId: getSystemCVEAllowlist
tags:
- SystemCVEAllowlist
responses:
'200':
description: Successfully retrieved the CVE allowlist.
schema:
$ref: "#/definitions/CVEAllowlist"
'401':
$ref: '#/responses/401'
'500':
$ref: '#/responses/500'
put:
summary: Update the system level allowlist of CVE.
description: This API overwrites the system level allowlist of CVE with the list in request body. Only system Admin
has permission to call this API.
operationId: putSystemCVEAllowlist
tags:
- SystemCVEAllowlist
parameters:
- in: body
name: allowlist
description: The allowlist with new content
schema:
$ref: "#/definitions/CVEAllowlist"
responses:
'200':
description: Successfully updated the CVE allowlist.
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'500':
$ref: '#/responses/500'
/system/scanAll/schedule:
get:
summary: Get scan all's schedule.

View File

@ -1,71 +0,0 @@
// 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 dao
import (
"encoding/json"
"fmt"
"time"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/lib/log"
)
// CreateCVEAllowlist creates the CVE allowlist
func CreateCVEAllowlist(l models.CVEAllowlist) (int64, error) {
o := GetOrmer()
now := time.Now()
l.CreationTime = now
l.UpdateTime = now
itemsBytes, _ := json.Marshal(l.Items)
l.ItemsText = string(itemsBytes)
return o.Insert(&l)
}
// UpdateCVEAllowlist Updates the vulnerability white list to DB
func UpdateCVEAllowlist(l models.CVEAllowlist) (int64, error) {
o := GetOrmer()
now := time.Now()
l.UpdateTime = now
itemsBytes, _ := json.Marshal(l.Items)
l.ItemsText = string(itemsBytes)
id, err := o.InsertOrUpdate(&l, "project_id")
return id, err
}
// GetCVEAllowlist Gets the CVE allowlist of the project based on the project ID in parameter
func GetCVEAllowlist(pid int64) (*models.CVEAllowlist, error) {
o := GetOrmer()
qs := o.QueryTable(&models.CVEAllowlist{})
qs = qs.Filter("ProjectID", pid)
r := []*models.CVEAllowlist{}
_, err := qs.All(&r)
if err != nil {
return nil, fmt.Errorf("failed to get CVE allowlist for project %d, error: %v", pid, err)
}
if len(r) == 0 {
return nil, nil
} else if len(r) > 1 {
log.Infof("Multiple CVE allowlists found for project %d, length: %d, returning first element.", pid, len(r))
}
items := []models.CVEAllowlistItem{}
err = json.Unmarshal([]byte(r[0].ItemsText), &items)
if err != nil {
log.Errorf("Failed to decode item list, err: %v, text: %s", err, r[0].ItemsText)
return nil, err
}
r[0].Items = items
return r[0], nil
}

View File

@ -1,55 +0,0 @@
// 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 dao
import (
"github.com/goharbor/harbor/src/common/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)
func TestUpdateAndGetCVEAllowlist(t *testing.T) {
require.Nil(t, ClearTable("cve_allowlist"))
l2, err := GetCVEAllowlist(5)
assert.Nil(t, err)
assert.Nil(t, l2)
longList := []models.CVEAllowlistItem{}
for i := 0; i < 50; i++ {
longList = append(longList, models.CVEAllowlistItem{CVEID: "CVE-1999-0067"})
}
e := int64(1573254000)
in1 := models.CVEAllowlist{ProjectID: 3, Items: longList, ExpiresAt: &e}
_, err = UpdateCVEAllowlist(in1)
require.Nil(t, err)
// assert.Equal(t, int64(1), n)
out1, err := GetCVEAllowlist(3)
require.Nil(t, err)
assert.Equal(t, int64(3), out1.ProjectID)
assert.Equal(t, longList, out1.Items)
assert.Equal(t, e, *out1.ExpiresAt)
sysCVEs := []models.CVEAllowlistItem{
{CVEID: "CVE-2019-10164"},
{CVEID: "CVE-2017-12345"},
}
in3 := models.CVEAllowlist{Items: sysCVEs}
_, err = UpdateCVEAllowlist(in3)
require.Nil(t, err)
require.Nil(t, ClearTable("cve_allowlist"))
}

View File

@ -35,6 +35,5 @@ func init() {
new(NotificationJob),
new(ProjectBlob),
new(ArtifactAndBlob),
new(CVEAllowlist),
)
}

View File

@ -22,6 +22,7 @@ import (
"time"
"github.com/astaxie/beego/orm"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/lib/pq"
)
@ -36,20 +37,20 @@ const (
// Project holds the details of a project.
type Project struct {
ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"`
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
Name string `orm:"column(name)" json:"name" sort:"default"`
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
Deleted bool `orm:"column(deleted)" json:"deleted"`
OwnerName string `orm:"-" json:"owner_name"`
Role int `orm:"-" json:"current_user_role_id"`
RoleList []int `orm:"-" json:"current_user_role_ids"`
RepoCount int64 `orm:"-" json:"repo_count"`
ChartCount uint64 `orm:"-" json:"chart_count"`
Metadata map[string]string `orm:"-" json:"metadata"`
CVEAllowlist CVEAllowlist `orm:"-" json:"cve_allowlist"`
RegistryID int64 `orm:"column(registry_id)" json:"registry_id"`
ProjectID int64 `orm:"pk;auto;column(project_id)" json:"project_id"`
OwnerID int `orm:"column(owner_id)" json:"owner_id"`
Name string `orm:"column(name)" json:"name" sort:"default"`
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
Deleted bool `orm:"column(deleted)" json:"deleted"`
OwnerName string `orm:"-" json:"owner_name"`
Role int `orm:"-" json:"current_user_role_id"`
RoleList []int `orm:"-" json:"current_user_role_ids"`
RepoCount int64 `orm:"-" json:"repo_count"`
ChartCount uint64 `orm:"-" json:"chart_count"`
Metadata map[string]string `orm:"-" json:"metadata"`
CVEAllowlist models.CVEAllowlist `orm:"-" json:"cve_allowlist"`
RegistryID int64 `orm:"column(registry_id)" json:"registry_id"`
}
// GetMetadata ...
@ -242,10 +243,10 @@ type BaseProjectCollection struct {
// ProjectRequest holds informations that need for creating project API
type ProjectRequest struct {
Name string `json:"project_name"`
Public *int `json:"public"` // deprecated, reserved for project creation in replication
Metadata map[string]string `json:"metadata"`
CVEAllowlist CVEAllowlist `json:"cve_allowlist"`
Name string `json:"project_name"`
Public *int `json:"public"` // deprecated, reserved for project creation in replication
Metadata map[string]string `json:"metadata"`
CVEAllowlist models.CVEAllowlist `json:"cve_allowlist"`
StorageLimit *int64 `json:"storage_limit,omitempty"`
RegistryID int64 `json:"registry_id"`

View File

@ -74,4 +74,5 @@ const (
ResourceScanAll = Resource("scan-all")
ResourceSystemVolumes = Resource("system-volumes")
ResourceOIDCEndpoint = Resource("oidc-endpoint")
ResourceSystemCVEAllowList = Resource("system-cve-allowlist")
)

View File

@ -65,5 +65,7 @@ var (
{Resource: rbac.ResourceOIDCEndpoint, Action: rbac.ActionRead},
{Resource: rbac.ResourceLdapUser, Action: rbac.ActionCreate},
{Resource: rbac.ResourceLdapUser, Action: rbac.ActionList},
{Resource: rbac.ResourceSystemCVEAllowList, Action: rbac.ActionRead},
{Resource: rbac.ResourceSystemCVEAllowList, Action: rbac.ActionUpdate},
}
)

View File

@ -26,6 +26,7 @@ import (
car "github.com/goharbor/harbor/src/controller/artifact"
"github.com/goharbor/harbor/src/controller/tag"
"github.com/goharbor/harbor/src/lib/selector"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
ar "github.com/goharbor/harbor/src/pkg/artifact"
po "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy"
pr "github.com/goharbor/harbor/src/pkg/p2p/preheat/models/provider"
@ -119,7 +120,7 @@ func (suite *EnforcerTestSuite) SetupSuite() {
).Return(&models.Project{
ProjectID: 1,
Name: "library",
CVEAllowlist: models.CVEAllowlist{},
CVEAllowlist: models2.CVEAllowlist{},
Metadata: map[string]string{
proMetaKeyContentTrust: "true",
proMetaKeyVulnerability: "true",

View File

@ -23,11 +23,11 @@ import (
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/pkg/allowlist"
"github.com/goharbor/harbor/src/pkg/notification"
"github.com/goharbor/harbor/src/pkg/project"
"github.com/goharbor/harbor/src/pkg/project/metadata"
"github.com/goharbor/harbor/src/pkg/project/models"
"github.com/goharbor/harbor/src/pkg/scan/allowlist"
"github.com/goharbor/harbor/src/pkg/user"
)
@ -89,7 +89,7 @@ func (c *controller) Create(ctx context.Context, project *models.Project) (int64
return err
}
if err := c.allowlistMgr.CreateEmpty(projectID); err != nil {
if err := c.allowlistMgr.CreateEmpty(ctx, projectID); err != nil {
log.Errorf("failed to create CVE allowlist for project %s: %v", project.Name, err)
return err
}
@ -233,7 +233,7 @@ func (c *controller) Update(ctx context.Context, p *models.Project) error {
}
if p.CVEAllowlist.ProjectID == p.ProjectID {
if err := c.allowlistMgr.Set(p.ProjectID, p.CVEAllowlist); err != nil {
if err := c.allowlistMgr.Set(ctx, p.ProjectID, p.CVEAllowlist); err != nil {
return err
}
}
@ -285,7 +285,7 @@ func (c *controller) loadCVEAllowlists(ctx context.Context, projects models.Proj
}
for _, p := range projects {
wl, err := c.allowlistMgr.Get(p.ProjectID)
wl, err := c.allowlistMgr.Get(ctx, p.ProjectID)
if err != nil {
return err
}
@ -303,7 +303,7 @@ func (c *controller) loadEffectCVEAllowlists(ctx context.Context, projects model
for _, p := range projects {
if p.ReuseSysCVEAllowlist() {
wl, err := c.allowlistMgr.GetSys()
wl, err := c.allowlistMgr.GetSys(ctx)
if err != nil {
log.Errorf("get system CVE allowlist failed, error: %v", err)
return err
@ -312,7 +312,7 @@ func (c *controller) loadEffectCVEAllowlists(ctx context.Context, projects model
wl.ProjectID = p.ProjectID
p.CVEAllowlist = *wl
} else {
wl, err := c.allowlistMgr.Get(p.ProjectID)
wl, err := c.allowlistMgr.Get(ctx, p.ProjectID)
if err != nil {
return err
}

View File

@ -19,17 +19,17 @@ import (
"fmt"
"testing"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/lib/q"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/goharbor/harbor/src/pkg/project/models"
usermodels "github.com/goharbor/harbor/src/pkg/user/models"
ormtesting "github.com/goharbor/harbor/src/testing/lib/orm"
"github.com/goharbor/harbor/src/testing/mock"
allowlisttesting "github.com/goharbor/harbor/src/testing/pkg/allowlist"
"github.com/goharbor/harbor/src/testing/pkg/project"
"github.com/goharbor/harbor/src/testing/pkg/project/metadata"
"github.com/goharbor/harbor/src/testing/pkg/scan/allowlist"
"github.com/goharbor/harbor/src/testing/pkg/user"
"github.com/stretchr/testify/suite"
)
@ -42,8 +42,8 @@ func (suite *ControllerTestSuite) TestCreate() {
ctx := orm.NewContext(context.TODO(), &ormtesting.FakeOrmer{})
mgr := &project.Manager{}
allowlistMgr := &allowlist.Manager{}
allowlistMgr.On("CreateEmpty", mock.Anything).Return(nil)
allowlistMgr := &allowlisttesting.Manager{}
allowlistMgr.On("CreateEmpty", mock.Anything, mock.Anything).Return(nil)
metadataMgr := &metadata.Manager{}
@ -74,7 +74,7 @@ func (suite *ControllerTestSuite) TestGetByName() {
mgr.On("Get", ctx, "test").Return(nil, errors.NotFoundError(nil))
mgr.On("Get", ctx, "oops").Return(nil, fmt.Errorf("oops"))
allowlistMgr := &allowlist.Manager{}
allowlistMgr := &allowlisttesting.Manager{}
metadataMgr := &metadata.Manager{}
metadataMgr.On("Get", ctx, mock.Anything).Return(map[string]string{"public": "true"}, nil)
@ -103,7 +103,7 @@ func (suite *ControllerTestSuite) TestGetByName() {
}
{
allowlistMgr.On("Get", mock.Anything).Return(&commonmodels.CVEAllowlist{ProjectID: 1}, nil)
allowlistMgr.On("Get", mock.Anything, mock.Anything).Return(&models2.CVEAllowlist{ProjectID: 1}, nil)
p, err := c.GetByName(ctx, "library", WithCVEAllowlist())
suite.Nil(err)
suite.Equal("library", p.Name)

View File

@ -117,7 +117,6 @@ func init() {
beego.Router("/api/email/ping", &EmailAPI{}, "post:Ping")
beego.Router("/api/labels", &LabelAPI{}, "post:Post;get:List")
beego.Router("/api/labels/:id([0-9]+", &LabelAPI{}, "get:Get;put:Put;delete:Delete")
beego.Router("/api/system/CVEAllowlist", &SysCVEAllowlistAPI{}, "get:Get;put:Put")
beego.Router("/api/replication/adapters", &ReplicationAdapterAPI{}, "get:List")

View File

@ -1,81 +0,0 @@
// 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 api
import (
"errors"
"fmt"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/scan/allowlist"
"net/http"
)
// SysCVEAllowlistAPI Handles the requests to manage system level CVE allowlist
type SysCVEAllowlistAPI struct {
BaseController
manager allowlist.Manager
}
// Prepare validates the request initially
func (sca *SysCVEAllowlistAPI) Prepare() {
sca.BaseController.Prepare()
if !sca.SecurityCtx.IsAuthenticated() {
sca.SendUnAuthorizedError(errors.New("Unauthorized"))
return
}
if !sca.SecurityCtx.IsSysAdmin() && sca.Ctx.Request.Method != http.MethodGet {
msg := fmt.Sprintf("only system admin has permission issue %s request to this API", sca.Ctx.Request.Method)
log.Errorf(msg)
sca.SendForbiddenError(errors.New(msg))
return
}
sca.manager = allowlist.NewDefaultManager()
}
// Get handles the GET request to retrieve the system level CVE allowlist
func (sca *SysCVEAllowlistAPI) Get() {
l, err := sca.manager.GetSys()
if err != nil {
sca.SendInternalServerError(err)
return
}
sca.WriteJSONData(l)
}
// Put handles the PUT request to update the system level CVE allowlist
func (sca *SysCVEAllowlistAPI) Put() {
var l models.CVEAllowlist
if err := sca.DecodeJSONReq(&l); err != nil {
log.Errorf("Failed to decode JSON array from request")
sca.SendBadRequestError(err)
return
}
if l.ProjectID != 0 {
msg := fmt.Sprintf("Non-zero project ID for system CVE allowlist: %d.", l.ProjectID)
log.Error(msg)
sca.SendBadRequestError(errors.New(msg))
return
}
if err := sca.manager.SetSys(l); err != nil {
if allowlist.IsInvalidErr(err) {
log.Errorf("Invalid CVE allowlist: %v", err)
sca.SendBadRequestError(err)
return
}
sca.SendInternalServerError(err)
return
}
}

View File

@ -1,127 +0,0 @@
// 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 api
import (
"github.com/goharbor/harbor/src/common/models"
"net/http"
"testing"
)
func TestSysCVEAllowlistAPIGet(t *testing.T) {
url := "/api/system/CVEAllowlist"
cases := []*codeCheckingCase{
// 401
{
request: &testingRequest{
method: http.MethodGet,
url: url,
},
code: http.StatusUnauthorized,
},
// 200
{
request: &testingRequest{
method: http.MethodGet,
url: url,
credential: nonSysAdmin,
},
code: http.StatusOK,
},
}
runCodeCheckingCases(t, cases...)
}
func TestSysCVEAllowlistAPIPut(t *testing.T) {
url := "/api/system/CVEAllowlist"
s := int64(1573254000)
cases := []*codeCheckingCase{
// 401
{
request: &testingRequest{
method: http.MethodPut,
url: url,
},
code: http.StatusUnauthorized,
},
// 403
{
request: &testingRequest{
method: http.MethodPut,
url: url,
credential: nonSysAdmin,
},
code: http.StatusForbidden,
},
// 400
{
request: &testingRequest{
method: http.MethodPut,
url: url,
bodyJSON: []string{"CVE-1234-1234"},
credential: sysAdmin,
},
code: http.StatusBadRequest,
},
// 400
{
request: &testingRequest{
method: http.MethodPut,
url: url,
bodyJSON: models.CVEAllowlist{
ExpiresAt: &s,
Items: []models.CVEAllowlistItem{
{CVEID: "CVE-2019-12310"},
},
ProjectID: 2,
},
credential: sysAdmin,
},
code: http.StatusBadRequest,
},
// 400
{
request: &testingRequest{
method: http.MethodPut,
url: url,
bodyJSON: models.CVEAllowlist{
ExpiresAt: &s,
Items: []models.CVEAllowlistItem{
{CVEID: "CVE-2019-12310"},
{CVEID: "CVE-2019-12310"},
},
},
credential: sysAdmin,
},
code: http.StatusBadRequest,
},
// 200
{
request: &testingRequest{
method: http.MethodPut,
url: url,
bodyJSON: models.CVEAllowlist{
ExpiresAt: &s,
Items: []models.CVEAllowlistItem{
{CVEID: "CVE-2019-12310"},
{CVEID: "RHSA-2019:2237"},
},
},
credential: sysAdmin,
},
code: http.StatusOK,
},
}
runCodeCheckingCases(t, cases...)
}

View File

@ -0,0 +1,75 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"time"
beegoorm "github.com/astaxie/beego/orm"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
)
// DAO is the data access object interface for CVE allowlist
type DAO interface {
// Set creates or updates the CVE allowlist to DB based on the project ID in the input parm, if the project does not
// have a CVE allowlist, an empty allowlist will be created. The project ID should be 0 for system level CVE allowlist
Set(ctx context.Context, l models.CVEAllowlist) (int64, error)
// QueryByProjectID returns the CVE allowlist of the project based on the project ID in parameter. The project ID should be 0
// for system level CVE allowlist
QueryByProjectID(ctx context.Context, pid int64) (*models.CVEAllowlist, error)
}
// New ...
func New() DAO {
return &dao{}
}
func init() {
beegoorm.RegisterModel(new(models.CVEAllowlist))
}
type dao struct{}
func (d *dao) Set(ctx context.Context, l models.CVEAllowlist) (int64, error) {
ormer, err := orm.FromContext(ctx)
if err != nil {
return 0, err
}
now := time.Now()
l.CreationTime = now
l.UpdateTime = now
itemsBytes, _ := json.Marshal(l.Items)
l.ItemsText = string(itemsBytes)
return ormer.InsertOrUpdate(&l, "project_id")
}
func (d *dao) QueryByProjectID(ctx context.Context, pid int64) (*models.CVEAllowlist, error) {
ormer, err := orm.FromContext(ctx)
if err != nil {
return nil, err
}
qs := ormer.QueryTable(&models.CVEAllowlist{})
qs = qs.Filter("ProjectID", pid)
var r []models.CVEAllowlist
_, err = qs.All(&r)
if err != nil {
return nil, fmt.Errorf("failed to get CVE allowlist for project %d, error: %v", pid, err)
}
if len(r) == 0 {
return nil, nil
} else if len(r) > 1 {
log.Infof("Multiple CVE allowlists found for project %d, length: %d, returning first element.", pid, len(r))
}
items := []models.CVEAllowlistItem{}
err = json.Unmarshal([]byte(r[0].ItemsText), &items)
if err != nil {
log.Errorf("Failed to decode item list, err: %v, text: %s", err, r[0].ItemsText)
return nil, err
}
r[0].Items = items
return &r[0], nil
}

View File

@ -0,0 +1,57 @@
package dao
import (
"testing"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
htesting "github.com/goharbor/harbor/src/testing"
"github.com/stretchr/testify/suite"
)
type testSuite struct {
htesting.Suite
dao DAO
}
func (s *testSuite) SetupSuite() {
s.Suite.SetupSuite()
s.Suite.ClearSQLs = []string{
"DELETE FROM cve_allowlist WHERE 1 = 1",
}
s.dao = New()
}
func (s *testSuite) TestSetAndGet() {
s.TearDownSuite()
l, err := s.dao.QueryByProjectID(s.Context(), 5)
s.Nil(err)
s.Nil(l)
var longList []models.CVEAllowlistItem
for i := 0; i < 50; i++ {
longList = append(longList, models.CVEAllowlistItem{CVEID: "CVE-1999-0067"})
}
e := int64(1573254000)
in1 := models.CVEAllowlist{ProjectID: 3, Items: longList, ExpiresAt: &e}
_, err = s.dao.Set(s.Context(), in1)
s.Nil(err)
// assert.Equal(t, int64(1), n)
out1, err := s.dao.QueryByProjectID(s.Context(), 3)
s.Nil(err)
s.Equal(int64(3), out1.ProjectID)
s.Equal(longList, out1.Items)
s.Equal(e, *out1.ExpiresAt)
sysCVEs := []models.CVEAllowlistItem{
{CVEID: "CVE-2019-10164"},
{CVEID: "CVE-2017-12345"},
}
in3 := models.CVEAllowlist{Items: sysCVEs}
_, err = s.dao.Set(s.Context(), in3)
s.Nil(err)
}
func TestDaoTestSuite(t *testing.T) {
suite.Run(t, &testSuite{})
}

View File

@ -15,35 +15,39 @@
package allowlist
import (
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/common/models"
"context"
"github.com/goharbor/harbor/src/jobservice/logger"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/allowlist/dao"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
)
// Manager defines the interface of CVE allowlist manager, it support both system level and project level allowlists
type Manager interface {
// CreateEmpty creates empty allowlist for given project
CreateEmpty(projectID int64) error
CreateEmpty(ctx context.Context, projectID int64) error
// Set sets the allowlist for given project (create or update)
Set(projectID int64, list models.CVEAllowlist) error
Set(ctx context.Context, projectID int64, list models.CVEAllowlist) error
// Get gets the allowlist for given project
Get(projectID int64) (*models.CVEAllowlist, error)
Get(ctx context.Context, projectID int64) (*models.CVEAllowlist, error)
// SetSys sets system level allowlist
SetSys(list models.CVEAllowlist) error
SetSys(ctx context.Context, list models.CVEAllowlist) error
// GetSys gets system level allowlist
GetSys() (*models.CVEAllowlist, error)
GetSys(ctx context.Context) (*models.CVEAllowlist, error)
}
type defaultManager struct{}
type defaultManager struct {
dao dao.DAO
}
// CreateEmpty creates empty allowlist for given project
func (d *defaultManager) CreateEmpty(projectID int64) error {
func (d *defaultManager) CreateEmpty(ctx context.Context, projectID int64) error {
l := models.CVEAllowlist{
ProjectID: projectID,
Items: []models.CVEAllowlistItem{},
}
_, err := dao.CreateCVEAllowlist(l)
_, err := d.dao.Set(ctx, l)
if err != nil {
logger.Errorf("Failed to create empty CVE allowlist for project: %d, error: %v", projectID, err)
}
@ -51,18 +55,18 @@ func (d *defaultManager) CreateEmpty(projectID int64) error {
}
// Set sets the allowlist for given project (create or update)
func (d *defaultManager) Set(projectID int64, list models.CVEAllowlist) error {
func (d *defaultManager) Set(ctx context.Context, projectID int64, list models.CVEAllowlist) error {
list.ProjectID = projectID
if err := Validate(list); err != nil {
return err
}
_, err := dao.UpdateCVEAllowlist(list)
_, err := d.dao.Set(ctx, list)
return err
}
// Get gets the allowlist for given project
func (d *defaultManager) Get(projectID int64) (*models.CVEAllowlist, error) {
wl, err := dao.GetCVEAllowlist(projectID)
func (d *defaultManager) Get(ctx context.Context, projectID int64) (*models.CVEAllowlist, error) {
wl, err := d.dao.QueryByProjectID(ctx, projectID)
if err != nil {
return nil, err
}
@ -77,16 +81,16 @@ func (d *defaultManager) Get(projectID int64) (*models.CVEAllowlist, error) {
}
// SetSys sets the system level allowlist
func (d *defaultManager) SetSys(list models.CVEAllowlist) error {
return d.Set(0, list)
func (d *defaultManager) SetSys(ctx context.Context, list models.CVEAllowlist) error {
return d.Set(ctx, 0, list)
}
// GetSys gets the system level allowlist
func (d *defaultManager) GetSys() (*models.CVEAllowlist, error) {
return d.Get(0)
func (d *defaultManager) GetSys(ctx context.Context) (*models.CVEAllowlist, error) {
return d.Get(ctx, 0)
}
// NewDefaultManager return a new instance of defaultManager
func NewDefaultManager() Manager {
return &defaultManager{}
return &defaultManager{dao: dao.New()}
}

View File

@ -0,0 +1,99 @@
package allowlist
import (
"context"
"testing"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/goharbor/harbor/src/testing/mock"
"github.com/goharbor/harbor/src/testing/pkg/allowlist/dao"
"github.com/stretchr/testify/suite"
)
type mgrTestSuite struct {
suite.Suite
mgr Manager
dao *dao.DAO
}
func (mt *mgrTestSuite) SetupTest() {
mt.dao = &dao.DAO{}
mt.mgr = &defaultManager{
dao: mt.dao,
}
}
func (mt *mgrTestSuite) TestSet() {
mt.dao.On("Set", mock.Anything, models.CVEAllowlist{
ProjectID: 9,
Items: []models.CVEAllowlistItem{
{
CVEID: "testcve-1-1-1-1",
},
},
}).Return(int64(9), nil)
err := mt.mgr.Set(context.Background(), 9, models.CVEAllowlist{
Items: []models.CVEAllowlistItem{
{
CVEID: "testcve-1-1-1-1",
},
},
})
mt.Nil(err)
mt.dao.AssertExpectations(mt.T())
}
func (mt *mgrTestSuite) TestSetSys() {
mt.dao.On("Set", mock.Anything, models.CVEAllowlist{
ProjectID: 9,
Items: []models.CVEAllowlistItem{
{
CVEID: "testcve-1-1-1-1",
},
},
}).Return(int64(0), nil)
err := mt.mgr.Set(context.Background(), 9, models.CVEAllowlist{
Items: []models.CVEAllowlistItem{
{
CVEID: "testcve-1-1-1-1",
},
},
})
mt.Nil(err)
mt.dao.AssertExpectations(mt.T())
}
func (mt *mgrTestSuite) TestGet() {
mt.dao.On("QueryByProjectID", mock.Anything, int64(3)).Return(nil, nil)
l, err := mt.mgr.Get(context.Background(), 3)
mt.Nil(err)
mt.Equal(models.CVEAllowlist{
ProjectID: 3,
Items: []models.CVEAllowlistItem{},
}, *l)
}
func (mt *mgrTestSuite) TestGetSys() {
mt.dao.On("QueryByProjectID", mock.Anything, int64(0)).Return(&models.CVEAllowlist{
ProjectID: 0,
Items: []models.CVEAllowlistItem{
{
CVEID: "testcve-1-1-1-1",
},
},
}, nil)
l, err := mt.mgr.GetSys(context.Background())
mt.Nil(err)
mt.Equal(models.CVEAllowlist{
ProjectID: 0,
Items: []models.CVEAllowlistItem{
{
CVEID: "testcve-1-1-1-1",
},
},
}, *l)
}
func TestManagerTestSuite(t *testing.T) {
suite.Run(t, &mgrTestSuite{})
}

View File

@ -20,13 +20,13 @@ import (
// CVEAllowlist defines the data model for a CVE allowlist
type CVEAllowlist struct {
ID int64 `orm:"pk;auto;column(id)" json:"id"`
ID int64 `orm:"pk;auto;column(id)" json:"id,omitempty"`
ProjectID int64 `orm:"column(project_id)" json:"project_id"`
ExpiresAt *int64 `orm:"column(expires_at)" json:"expires_at,omitempty"`
Items []CVEAllowlistItem `orm:"-" json:"items"`
ItemsText string `orm:"column(items)" json:"-"`
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
CreationTime time.Time `orm:"column(creation_time);auto_now_add"`
UpdateTime time.Time `orm:"column(update_time);auto_now"`
}
// CVEAllowlistItem defines one item in the CVE allowlist

View File

@ -16,7 +16,8 @@ package allowlist
import (
"fmt"
"github.com/goharbor/harbor/src/common/models"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
)
type invalidErr struct {
@ -43,7 +44,7 @@ func IsInvalidErr(err error) bool {
const cveIDPattern = `^CVE-\d{4}-\d+$`
// Validate help validates the CVE allowlist, to ensure the CVE ID is valid and there's no duplication
func Validate(wl models.CVEAllowlist) error {
func Validate(wl models2.CVEAllowlist) error {
m := map[string]struct{}{}
// re := regexp.MustCompile(cveIDPattern)
for _, it := range wl.Items {

View File

@ -16,9 +16,10 @@ package allowlist
import (
"fmt"
"github.com/goharbor/harbor/src/common/models"
"github.com/stretchr/testify/assert"
"testing"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/stretchr/testify/assert"
)
func TestIsInvalidErr(t *testing.T) {
@ -48,24 +49,24 @@ func TestIsInvalidErr(t *testing.T) {
func TestValidate(t *testing.T) {
cases := []struct {
l models.CVEAllowlist
l models2.CVEAllowlist
noError bool
}{
{
l: models.CVEAllowlist{
l: models2.CVEAllowlist{
Items: nil,
},
noError: true,
},
{
l: models.CVEAllowlist{
Items: []models.CVEAllowlistItem{},
l: models2.CVEAllowlist{
Items: []models2.CVEAllowlistItem{},
},
noError: true,
},
{
l: models.CVEAllowlist{
Items: []models.CVEAllowlistItem{
l: models2.CVEAllowlist{
Items: []models2.CVEAllowlistItem{
{CVEID: "breakit"},
{CVEID: "breakit"},
},
@ -73,8 +74,8 @@ func TestValidate(t *testing.T) {
noError: false,
},
{
l: models.CVEAllowlist{
Items: []models.CVEAllowlistItem{
l: models2.CVEAllowlist{
Items: []models2.CVEAllowlistItem{
{CVEID: "CVE-2014-456132"},
{CVEID: "CVE-2014-7654321"},
},
@ -82,8 +83,8 @@ func TestValidate(t *testing.T) {
noError: true,
},
{
l: models.CVEAllowlist{
Items: []models.CVEAllowlistItem{
l: models2.CVEAllowlist{
Items: []models2.CVEAllowlistItem{
{CVEID: "CVE-2014-456132"},
{CVEID: "CVE-2014-456132"},
{CVEID: "CVE-2014-7654321"},

View File

@ -1,46 +0,0 @@
package allowlist
import (
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/lib/log"
"github.com/stretchr/testify/assert"
"os"
"testing"
)
func TestMain(m *testing.M) {
// databases := []string{"mysql", "sqlite"}
databases := []string{"postgresql"}
for _, database := range databases {
log.Infof("run test cases for database: %s", database)
result := 1
switch database {
case "postgresql":
dao.PrepareTestForPostgresSQL()
default:
log.Fatalf("invalid database: %s", database)
}
result = m.Run()
if result != 0 {
os.Exit(result)
}
}
}
func TestDefaultManager_CreateEmpty(t *testing.T) {
dm := NewDefaultManager()
assert.NoError(t, dm.CreateEmpty(99))
assert.Error(t, dm.CreateEmpty(99))
}
func TestDefaultManager_Get(t *testing.T) {
dm := NewDefaultManager()
// return empty list
l, err := dm.Get(1234)
assert.Nil(t, err)
assert.Empty(t, l.Items)
}

View File

@ -17,9 +17,9 @@ package report
import (
"reflect"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/jobservice/job"
"github.com/goharbor/harbor/src/lib/errors"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
"github.com/goharbor/harbor/src/pkg/scan/vuln"
@ -30,14 +30,14 @@ type Options struct {
// If it is set, the returned report will contains artifact digest for the vulnerabilities
ArtifactDigest string
// If it is set, the returned summary will not count the CVEs in the list in.
CVEAllowlist models.CVESet
CVEAllowlist models2.CVESet
}
// Option for getting the report w/ summary with func template way.
type Option func(options *Options)
// WithCVEAllowlist is an option of setting CVE allowlist.
func WithCVEAllowlist(set *models.CVESet) Option {
func WithCVEAllowlist(set *models2.CVESet) Option {
return func(options *Options) {
options.CVEAllowlist = *set
}

View File

@ -19,7 +19,7 @@ import (
"testing"
"time"
"github.com/goharbor/harbor/src/common/models"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/goharbor/harbor/src/pkg/scan/dao/scan"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
"github.com/goharbor/harbor/src/pkg/scan/vuln"
@ -105,7 +105,7 @@ func (suite *SummaryTestSuite) TestSummaryGenerateSummaryNoOptions() {
// TestSummaryGenerateSummaryWithOptions ...
func (suite *SummaryTestSuite) TestSummaryGenerateSummaryWithOptions() {
cveSet := make(models.CVESet)
cveSet := make(models2.CVESet)
cveSet["2019-0980-0909"] = struct{}{}
summaries, err := GenerateSummary(suite.r, WithCVEAllowlist(&cveSet))

View File

@ -18,7 +18,7 @@ import (
"encoding/json"
"fmt"
"github.com/goharbor/harbor/src/common/models"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
)
@ -150,7 +150,7 @@ func (l *VulnerabilityItemList) Add(items ...*VulnerabilityItem) {
}
// GetSeveritySummaryAndByPassed returns the Severity Summary and ByPassed by allowlist for the l
func (l *VulnerabilityItemList) GetSeveritySummaryAndByPassed(allowlist models.CVESet) (Severity, *VulnerabilitySummary, []string) {
func (l *VulnerabilityItemList) GetSeveritySummaryAndByPassed(allowlist models2.CVESet) (Severity, *VulnerabilitySummary, []string) {
sum := &VulnerabilitySummary{
Total: len(l.Items()),
Summary: make(SeveritySummary),

View File

@ -19,7 +19,7 @@ import (
"reflect"
"testing"
"github.com/goharbor/harbor/src/common/models"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
"github.com/stretchr/testify/assert"
)
@ -108,7 +108,7 @@ func TestGetSummarySeverityAndByPassed(t *testing.T) {
Medium: 1,
}
severity, sum, byPassed := l.GetSeveritySummaryAndByPassed(models.CVESet{})
severity, sum, byPassed := l.GetSeveritySummaryAndByPassed(models2.CVESet{})
assert.Equal(3, sum.Total)
assert.Equal(1, sum.Fixable)
assert.Equal(s, sum.Summary)
@ -121,7 +121,7 @@ func TestGetSummarySeverityAndByPassed(t *testing.T) {
Low: 2,
}
cveSet := models.CVESet{}
cveSet := models2.CVESet{}
cveSet.Add("cve3")
severity, sum, byPassed := l.GetSeveritySummaryAndByPassed(cveSet)

View File

@ -17,8 +17,8 @@ package vuln
import (
"time"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/jobservice/job"
models2 "github.com/goharbor/harbor/src/pkg/allowlist/models"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
)
@ -39,11 +39,11 @@ type NativeReportSummary struct {
TotalCount int `json:"-"`
CompleteCount int `json:"-"`
VulnerabilityItemList *VulnerabilityItemList `json:"-"`
CVESet models.CVESet `json:"-"`
CVESet models2.CVESet `json:"-"`
}
// UpdateSeveritySummaryAndByPassed update the Severity, Summary and CVEBypassed of the sum from l and s
func (sum *NativeReportSummary) UpdateSeveritySummaryAndByPassed(l *VulnerabilityItemList, s models.CVESet) {
func (sum *NativeReportSummary) UpdateSeveritySummaryAndByPassed(l *VulnerabilityItemList, s models2.CVESet) {
sum.VulnerabilityItemList = l
sum.CVESet = s
@ -88,7 +88,7 @@ func (sum *NativeReportSummary) Merge(another *NativeReportSummary) *NativeRepor
r.UpdateSeveritySummaryAndByPassed(
NewVulnerabilityItemList(sum.VulnerabilityItemList, another.VulnerabilityItemList),
models.NewCVESet(sum.CVESet, another.CVESet),
models2.NewCVESet(sum.CVESet, another.CVESet),
)
return r

View File

@ -31,26 +31,27 @@ import (
// New returns http handler for API V2.0
func New() http.Handler {
h, api, err := restapi.HandlerAPI(restapi.Config{
ArtifactAPI: newArtifactAPI(),
RepositoryAPI: newRepositoryAPI(),
AuditlogAPI: newAuditLogAPI(),
ScannerAPI: newScannerAPI(),
ScanAPI: newScanAPI(),
ScanAllAPI: newScanAllAPI(),
ProjectAPI: newProjectAPI(),
PreheatAPI: newPreheatAPI(),
IconAPI: newIconAPI(),
RobotAPI: newRobotAPI(),
Robotv1API: newRobotV1API(),
ReplicationAPI: newReplicationAPI(),
SysteminfoAPI: newSystemInfoAPI(),
PingAPI: newPingAPI(),
LdapAPI: newLdapAPI(),
GCAPI: newGCAPI(),
QuotaAPI: newQuotaAPI(),
RetentionAPI: newRetentionAPI(),
ImmutableAPI: newImmutableAPI(),
OidcAPI: newOIDCAPI(),
ArtifactAPI: newArtifactAPI(),
RepositoryAPI: newRepositoryAPI(),
AuditlogAPI: newAuditLogAPI(),
ScannerAPI: newScannerAPI(),
ScanAPI: newScanAPI(),
ScanAllAPI: newScanAllAPI(),
ProjectAPI: newProjectAPI(),
PreheatAPI: newPreheatAPI(),
IconAPI: newIconAPI(),
RobotAPI: newRobotAPI(),
Robotv1API: newRobotV1API(),
ReplicationAPI: newReplicationAPI(),
SysteminfoAPI: newSystemInfoAPI(),
PingAPI: newPingAPI(),
LdapAPI: newLdapAPI(),
GCAPI: newGCAPI(),
QuotaAPI: newQuotaAPI(),
RetentionAPI: newRetentionAPI(),
ImmutableAPI: newImmutableAPI(),
OidcAPI: newOIDCAPI(),
SystemCVEAllowlistAPI: newSystemCVEAllowListAPI(),
})
if err != nil {
log.Fatal(err)

View File

@ -0,0 +1,36 @@
package model
import (
"github.com/go-openapi/strfmt"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
svrmodels "github.com/goharbor/harbor/src/server/v2.0/models"
)
// CVEAllowlist model
type CVEAllowlist struct {
*models.CVEAllowlist
}
// ToSwagger converts the model to swagger model
func (l *CVEAllowlist) ToSwagger() *svrmodels.CVEAllowlist {
res := &svrmodels.CVEAllowlist{
ID: l.ID,
Items: []*svrmodels.CVEAllowlistItem{},
ProjectID: l.ProjectID,
ExpiresAt: l.ExpiresAt,
CreationTime: strfmt.DateTime(l.CreationTime),
UpdateTime: strfmt.DateTime(l.UpdateTime),
}
for _, it := range l.Items {
cveItem := &svrmodels.CVEAllowlistItem{
CVEID: it.CVEID,
}
res.Items = append(res.Items, cveItem)
}
return res
}
// NewCVEAllowlist ...
func NewCVEAllowlist(l *models.CVEAllowlist) *CVEAllowlist {
return &CVEAllowlist{l}
}

View File

@ -0,0 +1,64 @@
// 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 handler
import (
"context"
"github.com/go-openapi/runtime/middleware"
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/pkg/allowlist"
"github.com/goharbor/harbor/src/pkg/allowlist/models"
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
"github.com/goharbor/harbor/src/server/v2.0/restapi/operations/system_cve_allowlist"
)
type systemCVEAllowListAPI struct {
BaseAPI
mgr allowlist.Manager
}
func newSystemCVEAllowListAPI() *systemCVEAllowListAPI {
return &systemCVEAllowListAPI{
mgr: allowlist.NewDefaultManager(),
}
}
func (s systemCVEAllowListAPI) PutSystemCVEAllowlist(ctx context.Context, params system_cve_allowlist.PutSystemCVEAllowlistParams) middleware.Responder {
if err := s.RequireSystemAccess(ctx, rbac.ActionUpdate, rbac.ResourceSystemCVEAllowList); err != nil {
return s.SendError(ctx, err)
}
l := models.CVEAllowlist{}
l.ExpiresAt = params.Allowlist.ExpiresAt
for _, it := range params.Allowlist.Items {
l.Items = append(l.Items, models.CVEAllowlistItem{CVEID: it.CVEID})
}
if err := s.mgr.SetSys(ctx, l); err != nil {
return s.SendError(ctx, err)
}
return system_cve_allowlist.NewPutSystemCVEAllowlistOK()
}
func (s systemCVEAllowListAPI) GetSystemCVEAllowlist(ctx context.Context, params system_cve_allowlist.GetSystemCVEAllowlistParams) middleware.Responder {
if err := s.RequireAuthenticated(ctx); err != nil {
return s.SendError(ctx, err)
}
l, err := s.mgr.GetSys(ctx)
if err != nil {
return s.SendError(ctx, err)
}
return system_cve_allowlist.NewGetSystemCVEAllowlistOK().WithPayload(model.NewCVEAllowlist(l).ToSwagger())
}

View File

@ -38,8 +38,6 @@ func registerLegacyRoutes() {
beego.Router("/api/"+version+"/projects/:id([0-9]+)/metadatas/?:name", &api.MetadataAPI{}, "get:Get")
beego.Router("/api/"+version+"/projects/:id([0-9]+)/metadatas/", &api.MetadataAPI{}, "post:Post")
beego.Router("/api/"+version+"/system/CVEAllowlist", &api.SysCVEAllowlistAPI{}, "get:Get;put:Put")
beego.Router("/api/"+version+"/replication/adapters", &api.ReplicationAdapterAPI{}, "get:List")
beego.Router("/api/"+version+"/replication/adapterinfos", &api.ReplicationAdapterAPI{}, "get:ListAdapterInfos")
beego.Router("/api/"+version+"/replication/policies", &api.ReplicationPolicyAPI{}, "get:List;post:Create")

View File

@ -0,0 +1,60 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package dao
import (
context "context"
mock "github.com/stretchr/testify/mock"
models "github.com/goharbor/harbor/src/pkg/allowlist/models"
)
// DAO is an autogenerated mock type for the DAO type
type DAO struct {
mock.Mock
}
// QueryByProjectID provides a mock function with given fields: ctx, pid
func (_m *DAO) QueryByProjectID(ctx context.Context, pid int64) (*models.CVEAllowlist, error) {
ret := _m.Called(ctx, pid)
var r0 *models.CVEAllowlist
if rf, ok := ret.Get(0).(func(context.Context, int64) *models.CVEAllowlist); ok {
r0 = rf(ctx, pid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.CVEAllowlist)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, pid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Set provides a mock function with given fields: ctx, l
func (_m *DAO) Set(ctx context.Context, l models.CVEAllowlist) (int64, error) {
ret := _m.Called(ctx, l)
var r0 int64
if rf, ok := ret.Get(0).(func(context.Context, models.CVEAllowlist) int64); ok {
r0 = rf(ctx, l)
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, models.CVEAllowlist) error); ok {
r1 = rf(ctx, l)
} else {
r1 = ret.Error(1)
}
return r0, r1
}

View File

@ -0,0 +1,103 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package robot
import (
context "context"
models "github.com/goharbor/harbor/src/pkg/allowlist/models"
mock "github.com/stretchr/testify/mock"
)
// Manager is an autogenerated mock type for the Manager type
type Manager struct {
mock.Mock
}
// CreateEmpty provides a mock function with given fields: ctx, projectID
func (_m *Manager) CreateEmpty(ctx context.Context, projectID int64) error {
ret := _m.Called(ctx, projectID)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, projectID)
} else {
r0 = ret.Error(0)
}
return r0
}
// Get provides a mock function with given fields: ctx, projectID
func (_m *Manager) Get(ctx context.Context, projectID int64) (*models.CVEAllowlist, error) {
ret := _m.Called(ctx, projectID)
var r0 *models.CVEAllowlist
if rf, ok := ret.Get(0).(func(context.Context, int64) *models.CVEAllowlist); ok {
r0 = rf(ctx, projectID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.CVEAllowlist)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, projectID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetSys provides a mock function with given fields: ctx
func (_m *Manager) GetSys(ctx context.Context) (*models.CVEAllowlist, error) {
ret := _m.Called(ctx)
var r0 *models.CVEAllowlist
if rf, ok := ret.Get(0).(func(context.Context) *models.CVEAllowlist); ok {
r0 = rf(ctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.CVEAllowlist)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Set provides a mock function with given fields: ctx, projectID, list
func (_m *Manager) Set(ctx context.Context, projectID int64, list models.CVEAllowlist) error {
ret := _m.Called(ctx, projectID, list)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64, models.CVEAllowlist) error); ok {
r0 = rf(ctx, projectID, list)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetSys provides a mock function with given fields: ctx, list
func (_m *Manager) SetSys(ctx context.Context, list models.CVEAllowlist) error {
ret := _m.Called(ctx, list)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, models.CVEAllowlist) error); ok {
r0 = rf(ctx, list)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@ -21,7 +21,6 @@ package pkg
//go:generate mockery --case snake --dir ../../pkg/project/metadata --name Manager --output ./project/metadata --outpkg metadata
//go:generate mockery --case snake --dir ../../pkg/quota --name Manager --output ./quota --outpkg quota
//go:generate mockery --case snake --dir ../../pkg/quota/driver --name Driver --output ./quota/driver --outpkg driver
//go:generate mockery --case snake --dir ../../pkg/scan/allowlist --name Manager --output ./scan/allowlist --outpkg allowlist
//go:generate mockery --case snake --dir ../../pkg/scan/report --name Manager --output ./scan/report --outpkg report
//go:generate mockery --case snake --dir ../../pkg/scan/rest/v1 --all --output ./scan/rest/v1 --outpkg v1
//go:generate mockery --case snake --dir ../../pkg/scan/scanner --all --output ./scan/scanner --outpkg scanner
@ -36,3 +35,5 @@ package pkg
//go:generate mockery --case snake --dir ../../pkg/repository/dao --name DAO --output ./repository/dao --outpkg dao
//go:generate mockery --case snake --dir ../../pkg/immutable/dao --name DAO --output ./immutable/dao --outpkg dao
//go:generate mockery --case snake --dir ../../pkg/ldap --name Manager --output ./ldap --outpkg ldap
//go:generate mockery --case snake --dir ../../pkg/allowlist --name Manager --output ./allowlist --outpkg robot
//go:generate mockery --case snake --dir ../../pkg/allowlist/dao --name DAO --output ./allowlist/dao --outpkg dao

View File

@ -1,101 +0,0 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package allowlist
import (
models "github.com/goharbor/harbor/src/common/models"
mock "github.com/stretchr/testify/mock"
)
// Manager is an autogenerated mock type for the Manager type
type Manager struct {
mock.Mock
}
// CreateEmpty provides a mock function with given fields: projectID
func (_m *Manager) CreateEmpty(projectID int64) error {
ret := _m.Called(projectID)
var r0 error
if rf, ok := ret.Get(0).(func(int64) error); ok {
r0 = rf(projectID)
} else {
r0 = ret.Error(0)
}
return r0
}
// Get provides a mock function with given fields: projectID
func (_m *Manager) Get(projectID int64) (*models.CVEAllowlist, error) {
ret := _m.Called(projectID)
var r0 *models.CVEAllowlist
if rf, ok := ret.Get(0).(func(int64) *models.CVEAllowlist); ok {
r0 = rf(projectID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.CVEAllowlist)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(int64) error); ok {
r1 = rf(projectID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetSys provides a mock function with given fields:
func (_m *Manager) GetSys() (*models.CVEAllowlist, error) {
ret := _m.Called()
var r0 *models.CVEAllowlist
if rf, ok := ret.Get(0).(func() *models.CVEAllowlist); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.CVEAllowlist)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Set provides a mock function with given fields: projectID, list
func (_m *Manager) Set(projectID int64, list models.CVEAllowlist) error {
ret := _m.Called(projectID, list)
var r0 error
if rf, ok := ret.Get(0).(func(int64, models.CVEAllowlist) error); ok {
r0 = rf(projectID, list)
} else {
r0 = ret.Error(0)
}
return r0
}
// SetSys provides a mock function with given fields: list
func (_m *Manager) SetSys(list models.CVEAllowlist) error {
ret := _m.Called(list)
var r0 error
if rf, ok := ret.Get(0).(func(models.CVEAllowlist) error); ok {
r0 = rf(list)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@ -28,7 +28,7 @@ def get_endpoint():
def _create_client(server, credential, debug, api_type="products"):
cfg = None
if api_type in ('projectv2', 'artifact', 'repository', 'scanner', 'scan', 'scanall', 'preheat', 'quota', 'replication', 'robot', 'gc', 'retention', "immutable"):
if api_type in ('projectv2', 'artifact', 'repository', 'scanner', 'scan', 'scanall', 'preheat', 'quota', 'replication', 'robot', 'gc', 'retention', "immutable", "system_cve_allowlist"):
cfg = v2_swagger_client.Configuration()
else:
cfg = swagger_client.Configuration()
@ -66,6 +66,7 @@ def _create_client(server, credential, debug, api_type="products"):
"gc": v2_swagger_client.GcApi(v2_swagger_client.ApiClient(cfg)),
"retention": v2_swagger_client.RetentionApi(v2_swagger_client.ApiClient(cfg)),
"immutable": v2_swagger_client.ImmutableApi(v2_swagger_client.ApiClient(cfg)),
"system_cve_allowlist": v2_swagger_client.SystemCVEAllowlistApi(v2_swagger_client.ApiClient(cfg)),
}.get(api_type,'Error: Wrong API type')
def _assert_status_code(expect_code, return_code, err_msg = r"HTTPS status code s not as we expected. Expected {}, while actual HTTPS status code is {}."):

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
import base
import v2_swagger_client
from v2_swagger_client.rest import ApiException
class SystemCVEAllowlist(base.Base, object):
def __init__(self):
super(SystemCVEAllowlist, self).__init__(api_type = "system_cve_allowlist")
def set_cve_allowlist(self, expires_at=None, expected_status_code=200, *cve_ids, **kwargs):
client = self._get_client(**kwargs)
cve_list = [v2_swagger_client.CVEAllowlistItem(cve_id=c) for c in cve_ids]
allowlist = v2_swagger_client.CVEAllowlist(expires_at=expires_at, items=cve_list)
try:
r = client.put_system_cve_allowlist_with_http_info(allowlist=allowlist, _preload_content=False)
except ApiException as e:
base._assert_status_code(expected_status_code, e.status)
else:
base._assert_status_code(expected_status_code, r.status)
def get_cve_allowlist(self, **kwargs):
client = self._get_client(**kwargs)
return client.get_system_cve_allowlist()

View File

@ -1,13 +1,14 @@
from __future__ import absolute_import
import unittest
import swagger_client
import time
from testutils import ADMIN_CLIENT, TEARDOWN, suppress_urllib3_warning
from library.user import User
from library.system import System
from library.system_cve_allowlist import SystemCVEAllowlist
import v2_swagger_client
class TestSysCVEAllowlist(unittest.TestCase):
"""
@ -31,6 +32,8 @@ class TestSysCVEAllowlist(unittest.TestCase):
def setUp(self):
self.user = User()
self.system = System()
self.system_cve_allowlist = SystemCVEAllowlist()
user_ra_password = "Aa123456"
print("Setup: Creating user for test")
user_ra_id, user_ra_name = self.user.create_user(user_password=user_ra_password, **ADMIN_CLIENT)
@ -43,31 +46,31 @@ class TestSysCVEAllowlist(unittest.TestCase):
@unittest.skipIf(TEARDOWN == False, "Test data won't be erased.")
def tearDown(self):
print("TearDown: Clearing the Allowlist")
self.system.set_cve_allowlist(**ADMIN_CLIENT)
self.system_cve_allowlist.set_cve_allowlist(**ADMIN_CLIENT)
print("TearDown: Deleting user: %d" % self.user_ra_id)
self.user.delete_user(self.user_ra_id, **ADMIN_CLIENT)
def testSysCVEAllowlist(self):
# 1. User(RA) reads the system level CVE allowlist and it's empty.
wl = self.system.get_cve_allowlist(**self.USER_RA_CLIENT)
wl = self.system_cve_allowlist.get_cve_allowlist(**self.USER_RA_CLIENT)
self.assertEqual(0, len(wl.items), "The initial system level CVE allowlist is not empty: %s" % wl.items)
# 2. User(RA) updates the system level CVE allowlist, verify it's failed.
cves = ['CVE-2019-12310']
self.system.set_cve_allowlist(None, 403, *cves, **self.USER_RA_CLIENT)
self.system_cve_allowlist.set_cve_allowlist(None, 403, *cves, **self.USER_RA_CLIENT)
# 3. Update user(RA) to system admin
self.user.update_user_role_as_sysadmin(self.user_ra_id, True, **ADMIN_CLIENT)
# 4. User(RA) updates the system level CVE allowlist, verify it's successful.
self.system.set_cve_allowlist(None, 200, *cves, **self.USER_RA_CLIENT)
self.system_cve_allowlist.set_cve_allowlist(None, 200, *cves, **self.USER_RA_CLIENT)
# 5. User(RA) reads the system level CVE allowlist, verify the CVE list is updated.
expect_wl = [swagger_client.CVEAllowlistItem(cve_id='CVE-2019-12310')]
wl = self.system.get_cve_allowlist(**self.USER_RA_CLIENT)
expect_wl = [v2_swagger_client.CVEAllowlistItem(cve_id='CVE-2019-12310')]
wl = self.system_cve_allowlist.get_cve_allowlist(**self.USER_RA_CLIENT)
self.assertIsNone(wl.expires_at)
self.assertEqual(expect_wl, wl.items)
# 6. User(RA) updates the expiration date of system level CVE allowlist.
exp = int(time.time()) + 3600
self.system.set_cve_allowlist(exp, 200, *cves, **self.USER_RA_CLIENT)
self.system_cve_allowlist.set_cve_allowlist(exp, 200, *cves, **self.USER_RA_CLIENT)
# 7. User(RA) reads the system level CVE allowlist, verify the expiration date is updated.
wl = self.system.get_cve_allowlist(**self.USER_RA_CLIENT)
wl = self.system_cve_allowlist.get_cve_allowlist(**self.USER_RA_CLIENT)
self.assertEqual(exp, wl.expires_at)
if __name__ == '__main__':