diff --git a/src/pkg/auditext/dao/dao_test.go b/src/pkg/auditext/dao/dao_test.go index 2296cc64be8..76ada028496 100644 --- a/src/pkg/auditext/dao/dao_test.go +++ b/src/pkg/auditext/dao/dao_test.go @@ -186,7 +186,7 @@ func TestPermitEventTypes(t *testing.T) { } // test other event types - otherEventTypes := permitEventTypes([]string{"create_artifact", "delete_artifact", "pull_artifact", "other_events"}) + otherEventTypes := permitEventTypes([]string{"create_artifact", "delete_artifact", "pull_artifact", "other"}) if len(otherEventTypes) != len(model.EventTypes) { t.Errorf("permitOtherEventTypes failed, it should include all event types") } diff --git a/src/pkg/auditext/event/basic.go b/src/pkg/auditext/event/basic.go index b2418e85117..5210fce9972 100644 --- a/src/pkg/auditext/event/basic.go +++ b/src/pkg/auditext/event/basic.go @@ -31,25 +31,25 @@ import ( ) const ( - createOp = "create" - updateOp = "update" - deleteOp = "delete" - resourceIDPattern = `^%v/(\d+)$` + createOp = "create" + updateOp = "update" + deleteOp = "delete" ) // ResolveIDToNameFunc is the function to resolve the resource name from resource id type ResolveIDToNameFunc func(string) string type Resolver struct { - BaseURLPattern string - ResourceType string - SucceedCodes []int + ResourceType string + SucceedCodes []int // SensitiveAttributes is the attributes that need to be redacted SensitiveAttributes []string // ShouldResolveName indicates if the resource name should be resolved before delete, if true, need to resolve the resource name before delete ShouldResolveName bool // IDToNameFunc is used to resolve the resource name from resource id IDToNameFunc ResolveIDToNameFunc + // ResourceIDPattern the URL pattern to match the resourceID + ResourceIDPattern string } // PreCheck check if the event should be captured and resolve the resource name if needed, if need to resolve the resource name, return the resource name @@ -61,9 +61,9 @@ func (e *Resolver) PreCheck(ctx context.Context, url string, method string) (cap // for delete operation on a resource has name, need to resolve the resource id to resource name before delete resName := "" if capture && method == http.MethodDelete && e.ShouldResolveName { - re := regexp.MustCompile(fmt.Sprintf(resourceIDPattern, e.BaseURLPattern)) + re := regexp.MustCompile(e.ResourceIDPattern) m := re.FindStringSubmatch(url) - if len(m) == 2 && e.IDToNameFunc != nil { + if len(m) >= 2 && e.IDToNameFunc != nil { resName = e.IDToNameFunc(m[1]) } } @@ -92,9 +92,9 @@ func (e *Resolver) Resolve(ce *commonevent.Metadata, event *event.Event) error { case createOp: if len(ce.ResponseLocation) > 0 { // extract resource id from response location - re := regexp.MustCompile(fmt.Sprintf(resourceIDPattern, e.BaseURLPattern)) + re := regexp.MustCompile(e.ResourceIDPattern) m := re.FindStringSubmatch(ce.ResponseLocation) - if len(m) != 2 { + if len(m) < 2 { return nil } evt.ResourceName = m[1] @@ -107,9 +107,9 @@ func (e *Resolver) Resolve(ce *commonevent.Metadata, event *event.Event) error { } case deleteOp: - re := regexp.MustCompile(fmt.Sprintf(resourceIDPattern, e.BaseURLPattern)) + re := regexp.MustCompile(e.ResourceIDPattern) m := re.FindStringSubmatch(ce.RequestURL) - if len(m) != 2 { + if len(m) < 2 { return nil } evt.ResourceName = m[1] @@ -118,9 +118,9 @@ func (e *Resolver) Resolve(ce *commonevent.Metadata, event *event.Event) error { } case updateOp: - re := regexp.MustCompile(fmt.Sprintf(resourceIDPattern, e.BaseURLPattern)) + re := regexp.MustCompile(e.ResourceIDPattern) m := re.FindStringSubmatch(ce.RequestURL) - if len(m) != 2 { + if len(m) < 2 { return nil } evt.ResourceName = m[1] diff --git a/src/pkg/auditext/event/basic_test.go b/src/pkg/auditext/event/basic_test.go index 700a44153ad..3fbc4fc8ebc 100644 --- a/src/pkg/auditext/event/basic_test.go +++ b/src/pkg/auditext/event/basic_test.go @@ -21,12 +21,12 @@ import ( func TestEventResolver_PreCheck(t *testing.T) { type fields struct { - BaseURLPattern string ResourceType string SucceedCodes []int SensitiveAttributes []string ShouldResolveName bool IDToNameFunc ResolveIDToNameFunc + ResourceIDPattern string } type args struct { ctx context.Context @@ -40,14 +40,14 @@ func TestEventResolver_PreCheck(t *testing.T) { wantCapture bool wantResourceName string }{ - {"test normal", fields{BaseURLPattern: `/api/v2.0/tests`, ResourceType: "test", SucceedCodes: []int{200}, ShouldResolveName: true, IDToNameFunc: func(string) string { return "test" }}, args{context.Background(), "/api/v2.0/tests/123", "DELETE"}, true, "test"}, - {"test resource name", fields{BaseURLPattern: `/api/v2.0/tests`, ResourceType: "test", SucceedCodes: []int{200}, ShouldResolveName: true, IDToNameFunc: func(string) string { return "test_resource_name" }}, args{context.Background(), "/api/v2.0/tests/234", "DELETE"}, true, "test_resource_name"}, - {"test no resource name", fields{BaseURLPattern: `/api/v2.0/tests`, ResourceType: "test", SucceedCodes: []int{200}, ShouldResolveName: true}, args{context.Background(), "/api/v2.0/tests/234", "GET"}, true, ""}, + {"test normal", fields{ResourceIDPattern: `/api/v2.0/tests/(\d+)`, ResourceType: "test", SucceedCodes: []int{200}, ShouldResolveName: true, IDToNameFunc: func(string) string { return "test" }}, args{context.Background(), "/api/v2.0/tests/123", "DELETE"}, true, "test"}, + {"test resource name", fields{ResourceIDPattern: `/api/v2.0/tests/(\d+)`, ResourceType: "test", SucceedCodes: []int{200}, ShouldResolveName: true, IDToNameFunc: func(string) string { return "test_resource_name" }}, args{context.Background(), "/api/v2.0/tests/234", "DELETE"}, true, "test_resource_name"}, + {"test no resource name", fields{ResourceIDPattern: `/api/v2.0/tests/(\d+)`, ResourceType: "test", SucceedCodes: []int{200}, ShouldResolveName: true}, args{context.Background(), "/api/v2.0/tests/234", "GET"}, true, ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { e := &Resolver{ - BaseURLPattern: tt.fields.BaseURLPattern, + ResourceIDPattern: tt.fields.ResourceIDPattern, ResourceType: tt.fields.ResourceType, SucceedCodes: tt.fields.SucceedCodes, SensitiveAttributes: tt.fields.SensitiveAttributes, diff --git a/src/pkg/auditext/event/user/user.go b/src/pkg/auditext/event/user/user.go index 5d96bd6056b..96d19722bf1 100644 --- a/src/pkg/auditext/event/user/user.go +++ b/src/pkg/auditext/event/user/user.go @@ -26,21 +26,21 @@ import ( pkgUser "github.com/goharbor/harbor/src/pkg/user" ) +const urlPattern = `^/api/v2.0/users/(\d+)(/password|/sysadmin)?$` + func init() { var userResolver = &userEventResolver{ Resolver: event.Resolver{ - BaseURLPattern: "/api/v2.0/users", ResourceType: rbac.ResourceUser.String(), SucceedCodes: []int{http.StatusCreated, http.StatusOK}, SensitiveAttributes: []string{"password"}, ShouldResolveName: true, IDToNameFunc: userIDToName, + ResourceIDPattern: urlPattern, }, } commonevent.RegisterResolver(`/api/v2.0/users$`, userResolver) - commonevent.RegisterResolver(`^/api/v2.0/users/\d+/password$`, userResolver) - commonevent.RegisterResolver(`^/api/v2.0/users/\d+/sysadmin$`, userResolver) - commonevent.RegisterResolver(`^/api/v2.0/users/\d+$`, userResolver) + commonevent.RegisterResolver(urlPattern, userResolver) } type userEventResolver struct { diff --git a/src/pkg/auditext/model/model.go b/src/pkg/auditext/model/model.go index 5338cac5a25..3dc820d39e9 100644 --- a/src/pkg/auditext/model/model.go +++ b/src/pkg/auditext/model/model.go @@ -20,7 +20,7 @@ import ( beego_orm "github.com/beego/beego/v2/client/orm" ) -const OtherEvents = "other_events" +const OtherEvents = "other" func init() { beego_orm.RegisterModel(&AuditLogExt{}) @@ -60,7 +60,7 @@ var EventTypes = []string{ "update_user", "create_robot", "delete_robot", - "update_configure", + "update_configuration", } // OtherEventTypes defines the types of other audit log event types excludes previous EventTypes: create_artifact, delete_artifact, pull_artifact