mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 10:15:35 +01:00
API for system CVE allowlist to new model (#14412)
Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
parent
4ef93565f3
commit
0d4992a41e
@ -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.
|
||||
|
@ -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
|
||||
}
|
@ -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"))
|
||||
}
|
@ -35,6 +35,5 @@ func init() {
|
||||
new(NotificationJob),
|
||||
new(ProjectBlob),
|
||||
new(ArtifactAndBlob),
|
||||
new(CVEAllowlist),
|
||||
)
|
||||
}
|
||||
|
@ -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"`
|
||||
|
@ -74,4 +74,5 @@ const (
|
||||
ResourceScanAll = Resource("scan-all")
|
||||
ResourceSystemVolumes = Resource("system-volumes")
|
||||
ResourceOIDCEndpoint = Resource("oidc-endpoint")
|
||||
ResourceSystemCVEAllowList = Resource("system-cve-allowlist")
|
||||
)
|
||||
|
@ -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},
|
||||
}
|
||||
)
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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...)
|
||||
}
|
75
src/pkg/allowlist/dao/dao.go
Normal file
75
src/pkg/allowlist/dao/dao.go
Normal 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
|
||||
}
|
57
src/pkg/allowlist/dao/dao_test.go
Normal file
57
src/pkg/allowlist/dao/dao_test.go
Normal 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{})
|
||||
}
|
@ -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()}
|
||||
}
|
99
src/pkg/allowlist/manager_test.go
Normal file
99
src/pkg/allowlist/manager_test.go
Normal 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{})
|
||||
}
|
@ -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
|
@ -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 {
|
@ -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"},
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
36
src/server/v2.0/handler/model/cve_allowlist.go
Normal file
36
src/server/v2.0/handler/model/cve_allowlist.go
Normal 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}
|
||||
}
|
64
src/server/v2.0/handler/sys_cve_allowlist.go
Normal file
64
src/server/v2.0/handler/sys_cve_allowlist.go
Normal 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())
|
||||
}
|
@ -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")
|
||||
|
60
src/testing/pkg/allowlist/dao/dao.go
Normal file
60
src/testing/pkg/allowlist/dao/dao.go
Normal 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
|
||||
}
|
103
src/testing/pkg/allowlist/manager.go
Normal file
103
src/testing/pkg/allowlist/manager.go
Normal 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
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
@ -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 {}."):
|
||||
|
24
tests/apitests/python/library/system_cve_allowlist.py
Normal file
24
tests/apitests/python/library/system_cve_allowlist.py
Normal 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()
|
@ -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__':
|
||||
|
Loading…
Reference in New Issue
Block a user