Add dao and manager for audit log ext (#21379)

Signed-off-by: stonezdj <stone.zhang@broadcom.com>
This commit is contained in:
stonezdj(Daojun Zhang) 2025-01-14 17:49:50 +08:00 committed by GitHub
parent cc6ace188d
commit 60798a49b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 1115 additions and 1 deletions

View File

@ -462,6 +462,16 @@ packages:
DAO:
config:
dir: testing/pkg/audit/dao
github.com/goharbor/harbor/src/pkg/auditext:
interfaces:
Manager:
config:
dir: testing/pkg/auditext
github.com/goharbor/harbor/src/pkg/auditext/dao:
interfaces:
DAO:
config:
dir: testing/pkg/auditext/dao
github.com/goharbor/harbor/src/pkg/systemartifact:
interfaces:
Manager:

View File

@ -337,3 +337,13 @@ func MostMatchSorter(a, b string, matchWord string) bool {
func IsLocalPath(path string) bool {
return len(path) == 0 || (strings.HasPrefix(path, "/") && !strings.HasPrefix(path, "//"))
}
// StringInSlice check if the string is in the slice
func StringInSlice(str string, slice []string) bool {
for _, s := range slice {
if s == str {
return true
}
}
return false
}

View File

@ -20,6 +20,7 @@ import (
"github.com/goharbor/harbor/src/jobservice/job"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/pkg/audit"
"github.com/goharbor/harbor/src/pkg/auditext"
"github.com/goharbor/harbor/src/pkg/user"
)
@ -27,6 +28,7 @@ const UserNameParam = "username"
type AuditLogsDataMasking struct {
manager audit.Manager
extManager auditext.Manager
userManager user.Manager
}
@ -58,6 +60,9 @@ func (a *AuditLogsDataMasking) init() {
if a.userManager == nil {
a.userManager = user.New()
}
if a.extManager == nil {
a.extManager = auditext.Mgr
}
}
func (a AuditLogsDataMasking) Run(ctx job.Context, params job.Parameters) error {
@ -69,7 +74,11 @@ func (a AuditLogsDataMasking) Run(ctx job.Context, params job.Parameters) error
return err
}
logger.Infof("Masking log entries for a user: %s", username)
return a.manager.UpdateUsername(ctx.SystemContext(), username, a.userManager.GenerateCheckSum(username))
err = a.manager.UpdateUsername(ctx.SystemContext(), username, a.userManager.GenerateCheckSum(username))
if err != nil {
return err
}
return a.extManager.UpdateUsername(ctx.SystemContext(), username, a.userManager.GenerateCheckSum(username))
}
func (a AuditLogsDataMasking) parseParams(params job.Parameters) (string, error) {

View File

@ -23,6 +23,7 @@ import (
"github.com/goharbor/harbor/src/jobservice/job"
mockjobservice "github.com/goharbor/harbor/src/testing/jobservice"
"github.com/goharbor/harbor/src/testing/pkg/audit"
"github.com/goharbor/harbor/src/testing/pkg/auditext"
"github.com/goharbor/harbor/src/testing/pkg/user"
)
@ -35,12 +36,14 @@ func TestAuditLogsCleanupJobValidateParams(t *testing.T) {
const validUsername = "user"
var (
manager = &audit.Manager{}
extManger = &auditext.Manager{}
userManager = &user.Manager{}
)
rep := &AuditLogsDataMasking{
manager: manager,
userManager: userManager,
extManager: extManger,
}
err := rep.Validate(nil)
// parameters are required
@ -61,6 +64,7 @@ func TestAuditLogsCleanupJobValidateParams(t *testing.T) {
ctx.On("GetLogger").Return(logger)
userManager.On("GenerateCheckSum", validUsername).Return("hash")
manager.On("UpdateUsername", context.TODO(), validUsername, "hash").Return(nil)
extManger.On("UpdateUsername", context.TODO(), validUsername, "hash").Return(nil)
err = rep.Run(ctx, validParams)
assert.Nil(t, err)

205
src/pkg/auditext/dao/dao.go Normal file
View File

@ -0,0 +1,205 @@
// 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 (
"context"
"strings"
beegorm "github.com/beego/beego/v2/client/orm"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/lib/errors"
"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/auditext/model"
)
// DAO is the data access object for audit log
type DAO interface {
// Create the audit log ext
Create(ctx context.Context, access *model.AuditLogExt) (id int64, err error)
// Count returns the total count of audit log ext according to the query
Count(ctx context.Context, query *q.Query) (total int64, err error)
// List audit log ext according to the query
List(ctx context.Context, query *q.Query) (access []*model.AuditLogExt, err error)
// Get the audit log ext specified by ID
Get(ctx context.Context, id int64) (access *model.AuditLogExt, err error)
// Delete the audit log ext specified by ID
Delete(ctx context.Context, id int64) (err error)
// Purge the audit log ext
Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error)
// UpdateUsername replaces username in matched records
UpdateUsername(ctx context.Context, username string, usernameReplace string) error
}
// New returns an instance of the default DAO
func New() DAO {
return &dao{}
}
type dao struct{}
func (d *dao) UpdateUsername(ctx context.Context, username string, usernameReplace string) error {
o, err := orm.FromContext(ctx)
if err != nil {
return err
}
_, err = o.Raw("UPDATE audit_log_ext SET username = ? WHERE username = ?", usernameReplace, username).Exec()
return err
}
// Count ...
func (d *dao) Count(ctx context.Context, query *q.Query) (int64, error) {
qs, err := orm.QuerySetterForCount(ctx, &model.AuditLogExt{}, query)
if err != nil {
return 0, err
}
return qs.Count()
}
// List ...
func (d *dao) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
audit := []*model.AuditLogExt{}
qs, err := orm.QuerySetter(ctx, &model.AuditLogExt{}, query)
if err != nil {
return nil, err
}
if _, err = qs.All(&audit); err != nil {
return nil, err
}
return audit, nil
}
// Get ...
func (d *dao) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
audit := &model.AuditLogExt{
ID: id,
}
ormer, err := orm.FromContext(ctx)
if err != nil {
return nil, err
}
if err := ormer.Read(audit); err != nil {
if e := orm.AsNotFoundError(err, "audit %d not found", id); e != nil {
err = e
}
return nil, err
}
return audit, nil
}
// Create ...
func (d *dao) Create(ctx context.Context, audit *model.AuditLogExt) (int64, error) {
ormer, err := orm.FromContext(ctx)
if err != nil {
return 0, err
}
// the max length of username in database is 255, replace the last
// three charaters with "..." if the length is greater than 256
if len(audit.Username) > 255 {
audit.Username = audit.Username[:252] + "..."
}
id, err := ormer.Insert(audit)
if err != nil {
return 0, err
}
return id, err
}
// Delete ...
func (d *dao) Delete(ctx context.Context, id int64) error {
ormer, err := orm.FromContext(ctx)
if err != nil {
return err
}
n, err := ormer.Delete(&model.AuditLogExt{
ID: id,
})
if err != nil {
return err
}
if n == 0 {
return errors.NotFoundError(nil).WithMessagef("access %d not found", id)
}
return nil
}
// Purge delete expired audit log ext
func (*dao) Purge(ctx context.Context, retentionHour int, includeEventTypes []string, dryRun bool) (int64, error) {
ormer, err := orm.FromContext(ctx)
if err != nil {
return 0, err
}
if dryRun {
return dryRunPurge(ormer, retentionHour, includeEventTypes)
}
filterEvents := permitEventTypes(includeEventTypes)
if len(filterEvents) == 0 {
log.Infof("no operation selected, skip to purge audit log")
return 0, nil
}
sql := "DELETE FROM audit_log_ext WHERE op_time < NOW() - ? * interval '1 hour' AND lower(operation || '_' || resource_type) IN ('" + strings.Join(filterEvents, "','") + "')"
log.Debugf("purge audit logs raw sql: %v", sql)
r, err := ormer.Raw(sql, retentionHour).Exec()
if err != nil {
log.Errorf("failed to purge audit log, error %v", err)
return 0, err
}
delRows, rErr := r.RowsAffected()
if rErr != nil {
log.Errorf("failed to purge audit log, error %v", rErr)
return 0, rErr
}
log.Infof("purged %d audit logs in the database", delRows)
return delRows, err
}
func dryRunPurge(ormer beegorm.QueryExecutor, retentionHour int, includeEventTypes []string) (int64, error) {
filterEvents := permitEventTypes(includeEventTypes)
if len(filterEvents) == 0 {
log.Infof("[DRYRUN]no operation selected, skip to purge audit log")
return 0, nil
}
sql := "SELECT count(1) cnt FROM audit_log_ext WHERE op_time < NOW() - ? * interval '1 hour' AND lower(operation || '_' || resource_type) IN ('" + strings.Join(filterEvents, "','") + "')"
log.Debugf("purge audit log count raw sql: %v", sql)
var cnt int64
err := ormer.Raw(sql, retentionHour).QueryRow(&cnt)
if err != nil {
log.Errorf("failed to dry run purge audit log, error %v", err)
return 0, err
}
log.Infof("[DRYRUN]purged %d audit logs in the database", cnt)
return cnt, nil
}
// permitEventTypes filter not allowed event type, if no event types specified, purge no operation, use this function to avoid SQL injection
func permitEventTypes(includeEventTypes []string) []string {
if includeEventTypes == nil {
return nil
}
var filterEvents []string
for _, e := range includeEventTypes {
event := strings.ToLower(e)
if utils.StringInSlice(event, model.EventTypes) {
filterEvents = append(filterEvents, e)
}
}
return filterEvents
}

View File

@ -0,0 +1,188 @@
// 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 (
"context"
"testing"
"time"
beegoorm "github.com/beego/beego/v2/client/orm"
"github.com/stretchr/testify/suite"
common_dao "github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/pkg/auditext/model"
)
type daoTestSuite struct {
suite.Suite
dao DAO
auditID int64
ctx context.Context
}
func (d *daoTestSuite) SetupSuite() {
d.dao = New()
common_dao.PrepareTestForPostgresSQL()
d.ctx = orm.NewContext(nil, beegoorm.NewOrm())
artifactID, err := d.dao.Create(d.ctx, &model.AuditLogExt{
Operation: "Create",
ResourceType: "user",
Resource: "user01",
Username: "admin",
OperationDescription: "Create user",
OperationResult: true,
OpTime: time.Now().AddDate(0, 0, -8),
})
d.Require().Nil(err)
d.auditID = artifactID
}
func (d *daoTestSuite) TearDownSuite() {
ormer, err := orm.FromContext(d.ctx)
d.Require().Nil(err)
_, err = ormer.Raw("delete from audit_log_ext").Exec()
d.Require().Nil(err)
}
func (d *daoTestSuite) TestList() {
// nil query
audits, err := d.dao.List(d.ctx, nil)
d.Require().Nil(err)
// query by repository ID and name
audits, err = d.dao.List(d.ctx, &q.Query{
Keywords: map[string]interface{}{
"Resource": "user01",
},
})
d.Require().Nil(err)
d.Require().Equal(1, len(audits))
d.Equal("admin", audits[0].Username)
}
func (d *daoTestSuite) TestGet() {
// get the non-exist tag
_, err := d.dao.Get(d.ctx, 10000)
d.Require().NotNil(err)
d.True(errors.IsErr(err, errors.NotFoundCode))
audit, err := d.dao.Get(d.ctx, d.auditID)
d.Require().Nil(err)
d.Require().NotNil(audit)
d.Equal(d.auditID, audit.ID)
}
func (d *daoTestSuite) TestCount() {
total, err := d.dao.Count(d.ctx, nil)
d.Require().Nil(err)
d.True(total > 0)
total, err = d.dao.Count(d.ctx, &q.Query{
Keywords: map[string]interface{}{
"Resource": "user01",
},
})
d.Require().Nil(err)
d.Equal(int64(1), total)
}
func (d *daoTestSuite) TestListPIDs() {
// get the non-exist tag
id1, err := d.dao.Create(d.ctx, &model.AuditLogExt{
Operation: "create",
ResourceType: "artifact",
Resource: "library/hello-world",
Username: "admin",
ProjectID: 11,
})
d.Require().Nil(err)
id2, err := d.dao.Create(d.ctx, &model.AuditLogExt{
Operation: "create",
ResourceType: "artifact",
Resource: "library/hello-world",
Username: "admin",
ProjectID: 12,
})
d.Require().Nil(err)
id3, err := d.dao.Create(d.ctx, &model.AuditLogExt{
Operation: "delete",
ResourceType: "artifact",
Resource: "library/hello-world",
Username: "admin",
ProjectID: 13,
})
d.Require().Nil(err)
// query by repository ID and name
ol := &q.OrList{}
for _, item := range []int64{11, 12, 13} {
ol.Values = append(ol.Values, item)
}
audits, err := d.dao.List(d.ctx, &q.Query{
Keywords: map[string]interface{}{
"ProjectID": ol,
},
})
d.Require().Nil(err)
d.Require().Equal(3, len(audits))
d.dao.Delete(d.ctx, id1)
d.dao.Delete(d.ctx, id2)
d.dao.Delete(d.ctx, id3)
}
func (d *daoTestSuite) TestCreate() {
audit := &model.AuditLogExt{
Operation: "create",
ResourceType: "user",
Resource: "user02",
OperationResult: true,
Username: "admin",
}
_, err := d.dao.Create(d.ctx, audit)
d.Require().Nil(err)
}
func (d *daoTestSuite) TestPurge() {
// try to purge the audit log ext with the time range of 30 days, false
result, err := d.dao.Purge(d.ctx, 24*30, []string{"create_user"}, true)
d.Require().Nil(err)
d.Require().Equal(int64(0), result)
// try to purge the audit log ext with the time range of 7 days, true
result1, err := d.dao.Purge(d.ctx, 24*7, []string{"create_user"}, true)
d.Require().Nil(err)
d.Require().Equal(int64(1), result1)
}
func TestDaoTestSuite(t *testing.T) {
suite.Run(t, &daoTestSuite{})
}
func TestPermitEventTypes(t *testing.T) {
// test permit event types
eventTypes := permitEventTypes([]string{"create_user", "delete_user", "delete_anything"})
if len(eventTypes) != 2 {
t.Errorf("permitEventTypes failed")
}
eventTypes2 := permitEventTypes([]string{})
if len(eventTypes2) != 0 {
t.Errorf("permitEventTypes failed")
}
}

View File

@ -0,0 +1,99 @@
// 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 auditext
import (
"context"
"github.com/goharbor/harbor/src/lib/config"
"github.com/goharbor/harbor/src/lib/q"
auditV1 "github.com/goharbor/harbor/src/pkg/audit"
"github.com/goharbor/harbor/src/pkg/auditext/dao"
"github.com/goharbor/harbor/src/pkg/auditext/model"
)
// Mgr is the global audit log manager instance
var Mgr = New()
// Manager is used for audit log management
type Manager interface {
// Count returns the total count of audit logs according to the query
Count(ctx context.Context, query *q.Query) (total int64, err error)
// List audit logs according to the query
List(ctx context.Context, query *q.Query) (audits []*model.AuditLogExt, err error)
// Get the audit log specified by ID
Get(ctx context.Context, id int64) (audit *model.AuditLogExt, err error)
// Create the audit log
Create(ctx context.Context, audit *model.AuditLogExt) (id int64, err error)
// Delete the audit log specified by ID
Delete(ctx context.Context, id int64) (err error)
// Purge delete the audit log with retention hours
Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error)
// UpdateUsername Replace all log records username with its hash
UpdateUsername(ctx context.Context, username string, replaceWith string) error
}
// New returns a default implementation of Manager
func New() Manager {
return &manager{
dao: dao.New(),
}
}
type manager struct {
dao dao.DAO
}
func (m *manager) UpdateUsername(ctx context.Context, username string, replaceWith string) error {
return m.dao.UpdateUsername(ctx, username, replaceWith)
}
// Count ...
func (m *manager) Count(ctx context.Context, query *q.Query) (int64, error) {
return m.dao.Count(ctx, query)
}
// List ...
func (m *manager) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
return m.dao.List(ctx, query)
}
// Get ...
func (m *manager) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
return m.dao.Get(ctx, id)
}
// Create ...
func (m *manager) Create(ctx context.Context, audit *model.AuditLogExt) (int64, error) {
if len(config.AuditLogForwardEndpoint(ctx)) > 0 {
auditV1.LogMgr.DefaultLogger(ctx).WithField("operator", audit.Username).
WithField("time", audit.OpTime).WithField("resourceType", audit.ResourceType).
Infof("action:%s, resource:%s", audit.Operation, audit.Resource)
}
if config.SkipAuditLogDatabase(ctx) {
return 0, nil
}
return m.dao.Create(ctx, audit)
}
// Purge ...
func (m *manager) Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error) {
return m.dao.Purge(ctx, retentionHour, includeOperations, dryRun)
}
// Delete ...
func (m *manager) Delete(ctx context.Context, id int64) error {
return m.dao.Delete(ctx, id)
}

View File

@ -0,0 +1,104 @@
// 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 auditext
import (
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
"github.com/goharbor/harbor/src/pkg/auditext/model"
_ "github.com/goharbor/harbor/src/pkg/config/db"
mockDAO "github.com/goharbor/harbor/src/testing/pkg/auditext/dao"
)
type managerTestSuite struct {
suite.Suite
mgr *manager
dao *mockDAO.DAO
}
func (m *managerTestSuite) SetupTest() {
m.dao = &mockDAO.DAO{}
m.mgr = &manager{
dao: m.dao,
}
}
func (m *managerTestSuite) TestCount() {
m.dao.On("Count", mock.Anything, mock.Anything).Return(int64(1), nil)
total, err := m.mgr.Count(nil, nil)
m.Require().Nil(err)
m.Equal(int64(1), total)
}
func (m *managerTestSuite) TestList() {
audit := &model.AuditLogExt{
ProjectID: 1,
Resource: "library/hello-world",
ResourceType: "artifact",
}
m.dao.On("List", mock.Anything, mock.Anything).Return([]*model.AuditLogExt{audit}, nil)
auditLogs, err := m.mgr.List(nil, nil)
m.Require().Nil(err)
m.Equal(1, len(auditLogs))
m.Equal(audit.Resource, auditLogs[0].Resource)
}
func (m *managerTestSuite) TestGet() {
audit := &model.AuditLogExt{
ProjectID: 1,
Resource: "library/hello-world",
ResourceType: "artifact",
}
m.dao.On("Get", mock.Anything, mock.Anything).Return(audit, nil)
au, err := m.mgr.Get(nil, 1)
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
m.Require().NotNil(au)
m.Equal(audit.Resource, au.Resource)
}
func (m *managerTestSuite) TestCreate() {
m.dao.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil)
id, err := m.mgr.Create(nil, &model.AuditLogExt{
ProjectID: 1,
Resource: "library/hello-world",
ResourceType: "artifact",
})
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
m.Equal(int64(1), id)
}
func (m *managerTestSuite) TestDelete() {
m.dao.On("Delete", mock.Anything, mock.Anything).Return(nil)
err := m.mgr.Delete(nil, 1)
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
}
func (m *managerTestSuite) TestPurge() {
m.dao.On("Purge", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
total, err := m.mgr.Purge(nil, 1, nil, false)
m.Require().Nil(err)
m.Equal(int64(1), total)
m.dao.AssertExpectations(m.T())
}
func TestManager(t *testing.T) {
suite.Run(t, &managerTestSuite{})
}

View File

@ -0,0 +1,62 @@
// 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 model
import (
"time"
beego_orm "github.com/beego/beego/v2/client/orm"
)
func init() {
beego_orm.RegisterModel(&AuditLogExt{})
}
// AuditLogExt is the model for audit log ext
type AuditLogExt struct {
ID int64 `orm:"pk;auto;column(id)" json:"id"`
ProjectID int64 `orm:"column(project_id)" json:"project_id"`
Operation string `orm:"column(operation)" json:"operation"`
OperationDescription string `orm:"column(op_desc)" json:"operation_description"`
OperationResult bool `orm:"column(op_result)" json:"operation_result"`
ResourceType string `orm:"column(resource_type)" json:"resource_type"`
Resource string `orm:"column(resource)" json:"resource"`
Username string `orm:"column(username)" json:"username"`
OpTime time.Time `orm:"column(op_time)" json:"op_time" sort:"default:desc"`
Payload string `orm:"-" json:"payload"`
}
// TableName for audit log
func (a *AuditLogExt) TableName() string {
return "audit_log_ext"
}
// EventTypes defines the types of audit log event
var EventTypes = []string{
"create_artifact",
"delete_artifact",
"pull_artifact",
"create_project",
"delete_project",
"delete_repository",
"login_user",
"logout_user",
"create_user",
"delete_user",
"update_user",
"create_robot",
"delete_robot",
"update_configure",
}

View File

@ -0,0 +1,212 @@
// Code generated by mockery v2.46.2. DO NOT EDIT.
package dao
import (
context "context"
mock "github.com/stretchr/testify/mock"
model "github.com/goharbor/harbor/src/pkg/auditext/model"
q "github.com/goharbor/harbor/src/lib/q"
)
// DAO is an autogenerated mock type for the DAO type
type DAO struct {
mock.Mock
}
// Count provides a mock function with given fields: ctx, query
func (_m *DAO) Count(ctx context.Context, query *q.Query) (int64, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for Count")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
r0 = rf(ctx, query)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Create provides a mock function with given fields: ctx, access
func (_m *DAO) Create(ctx context.Context, access *model.AuditLogExt) (int64, error) {
ret := _m.Called(ctx, access)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) (int64, error)); ok {
return rf(ctx, access)
}
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) int64); ok {
r0 = rf(ctx, access)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, *model.AuditLogExt) error); ok {
r1 = rf(ctx, access)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Delete provides a mock function with given fields: ctx, id
func (_m *DAO) Delete(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// Get provides a mock function with given fields: ctx, id
func (_m *DAO) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for Get")
}
var r0 *model.AuditLogExt
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64) (*model.AuditLogExt, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, int64) *model.AuditLogExt); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AuditLogExt)
}
}
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// List provides a mock function with given fields: ctx, query
func (_m *DAO) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for List")
}
var r0 []*model.AuditLogExt
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*model.AuditLogExt, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*model.AuditLogExt); ok {
r0 = rf(ctx, query)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.AuditLogExt)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Purge provides a mock function with given fields: ctx, retentionHour, includeOperations, dryRun
func (_m *DAO) Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error) {
ret := _m.Called(ctx, retentionHour, includeOperations, dryRun)
if len(ret) == 0 {
panic("no return value specified for Purge")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) (int64, error)); ok {
return rf(ctx, retentionHour, includeOperations, dryRun)
}
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) int64); ok {
r0 = rf(ctx, retentionHour, includeOperations, dryRun)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, int, []string, bool) error); ok {
r1 = rf(ctx, retentionHour, includeOperations, dryRun)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// UpdateUsername provides a mock function with given fields: ctx, username, usernameReplace
func (_m *DAO) UpdateUsername(ctx context.Context, username string, usernameReplace string) error {
ret := _m.Called(ctx, username, usernameReplace)
if len(ret) == 0 {
panic("no return value specified for UpdateUsername")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, username, usernameReplace)
} else {
r0 = ret.Error(0)
}
return r0
}
// NewDAO creates a new instance of DAO. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewDAO(t interface {
mock.TestingT
Cleanup(func())
}) *DAO {
mock := &DAO{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -0,0 +1,211 @@
// Code generated by mockery v2.46.2. DO NOT EDIT.
package auditext
import (
context "context"
model "github.com/goharbor/harbor/src/pkg/auditext/model"
mock "github.com/stretchr/testify/mock"
q "github.com/goharbor/harbor/src/lib/q"
)
// Manager is an autogenerated mock type for the Manager type
type Manager struct {
mock.Mock
}
// Count provides a mock function with given fields: ctx, query
func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for Count")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
r0 = rf(ctx, query)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Create provides a mock function with given fields: ctx, audit
func (_m *Manager) Create(ctx context.Context, audit *model.AuditLogExt) (int64, error) {
ret := _m.Called(ctx, audit)
if len(ret) == 0 {
panic("no return value specified for Create")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) (int64, error)); ok {
return rf(ctx, audit)
}
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) int64); ok {
r0 = rf(ctx, audit)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, *model.AuditLogExt) error); ok {
r1 = rf(ctx, audit)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Delete provides a mock function with given fields: ctx, id
func (_m *Manager) Delete(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// Get provides a mock function with given fields: ctx, id
func (_m *Manager) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for Get")
}
var r0 *model.AuditLogExt
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64) (*model.AuditLogExt, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, int64) *model.AuditLogExt); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AuditLogExt)
}
}
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// List provides a mock function with given fields: ctx, query
func (_m *Manager) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for List")
}
var r0 []*model.AuditLogExt
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*model.AuditLogExt, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*model.AuditLogExt); ok {
r0 = rf(ctx, query)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.AuditLogExt)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Purge provides a mock function with given fields: ctx, retentionHour, includeOperations, dryRun
func (_m *Manager) Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error) {
ret := _m.Called(ctx, retentionHour, includeOperations, dryRun)
if len(ret) == 0 {
panic("no return value specified for Purge")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) (int64, error)); ok {
return rf(ctx, retentionHour, includeOperations, dryRun)
}
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) int64); ok {
r0 = rf(ctx, retentionHour, includeOperations, dryRun)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, int, []string, bool) error); ok {
r1 = rf(ctx, retentionHour, includeOperations, dryRun)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// UpdateUsername provides a mock function with given fields: ctx, username, replaceWith
func (_m *Manager) UpdateUsername(ctx context.Context, username string, replaceWith string) error {
ret := _m.Called(ctx, username, replaceWith)
if len(ret) == 0 {
panic("no return value specified for UpdateUsername")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, username, replaceWith)
} else {
r0 = ret.Error(0)
}
return r0
}
// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewManager(t interface {
mock.TestingT
Cleanup(func())
}) *Manager {
mock := &Manager{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}