fix: skip to delete scan reports if the digest still referenced (#19110)

fix: skip to delete scan reports if the digest still referenced by other artifacts

Avoid to delete the scan reports in case the artifact deleted but still
referenced by the other artifacts.

Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
Chlins Zhang 2023-08-07 14:00:26 +08:00 committed by GitHub
parent 403b616a5a
commit a036e4a7b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 4 deletions

View File

@ -33,6 +33,8 @@ import (
"github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/lib/q" "github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/pkg"
pkgArt "github.com/goharbor/harbor/src/pkg/artifact"
"github.com/goharbor/harbor/src/pkg/scan/report" "github.com/goharbor/harbor/src/pkg/scan/report"
"github.com/goharbor/harbor/src/pkg/task" "github.com/goharbor/harbor/src/pkg/task"
) )
@ -70,6 +72,8 @@ type Handler struct {
execMgr task.ExecutionManager execMgr task.ExecutionManager
// reportMgr for managing scan reports // reportMgr for managing scan reports
reportMgr report.Manager reportMgr report.Manager
// artMgr for managing artifacts
artMgr pkgArt.Manager
once sync.Once once sync.Once
// pullCountStore caches the pull count group by repository // pullCountStore caches the pull count group by repository
@ -262,6 +266,7 @@ func (a *Handler) onPush(ctx context.Context, event *event.ArtifactEvent) error
func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) error { func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) error {
execMgr := task.ExecMgr execMgr := task.ExecMgr
reportMgr := report.Mgr reportMgr := report.Mgr
artMgr := pkg.ArtifactMgr
// for UT mock // for UT mock
if a.execMgr != nil { if a.execMgr != nil {
execMgr = a.execMgr execMgr = a.execMgr
@ -269,6 +274,9 @@ func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) erro
if a.reportMgr != nil { if a.reportMgr != nil {
reportMgr = a.reportMgr reportMgr = a.reportMgr
} }
if a.artMgr != nil {
artMgr = a.artMgr
}
ids := []int64{event.Artifact.ID} ids := []int64{event.Artifact.ID}
digests := []string{event.Artifact.Digest} digests := []string{event.Artifact.Digest}
@ -278,7 +286,20 @@ func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) erro
digests = append(digests, ref.ChildDigest) digests = append(digests, ref.ChildDigest)
} }
} }
// check if the digest also referenced by other artifacts, should exclude it to delete the scan report if still referenced by others.
unrefDigests := []string{}
for _, digest := range digests {
// with the base=* to query all artifacts includes untagged and references
count, err := artMgr.Count(ctx, q.New(q.KeyWords{"digest": digest, "base": "*"}))
if err != nil {
log.Errorf("failed to count the artifact with the digest %s, error: %v", digest, err)
continue
}
if count == 0 {
unrefDigests = append(unrefDigests, digest)
}
}
// clean up the scan executions of this artifact and it's references by id // clean up the scan executions of this artifact and it's references by id
log.Debugf("delete the associated scan executions of artifacts %v as the artifacts have been deleted", ids) log.Debugf("delete the associated scan executions of artifacts %v as the artifacts have been deleted", ids)
for _, id := range ids { for _, id := range ids {
@ -288,9 +309,9 @@ func (a *Handler) onDelete(ctx context.Context, event *event.ArtifactEvent) erro
} }
// clean up the scan reports of this artifact and it's references by digest // clean up the scan reports of this artifact and it's references by digest
log.Debugf("delete the associated scan reports of artifacts %v as the artifacts have been deleted", digests) log.Debugf("delete the associated scan reports of artifacts %v as the artifacts have been deleted", unrefDigests)
if err := reportMgr.DeleteByDigests(ctx, digests...); err != nil { if err := reportMgr.DeleteByDigests(ctx, unrefDigests...); err != nil {
log.Errorf("failed to delete scan reports of artifact %v, error: %v", digests, err) log.Errorf("failed to delete scan reports of artifact %v, error: %v", unrefDigests, err)
} }
return nil return nil

View File

@ -35,6 +35,8 @@ import (
"github.com/goharbor/harbor/src/pkg/tag" "github.com/goharbor/harbor/src/pkg/tag"
tagmodel "github.com/goharbor/harbor/src/pkg/tag/model/tag" tagmodel "github.com/goharbor/harbor/src/pkg/tag/model/tag"
scannerCtlMock "github.com/goharbor/harbor/src/testing/controller/scanner" scannerCtlMock "github.com/goharbor/harbor/src/testing/controller/scanner"
"github.com/goharbor/harbor/src/testing/mock"
artMock "github.com/goharbor/harbor/src/testing/pkg/artifact"
projectMock "github.com/goharbor/harbor/src/testing/pkg/project" projectMock "github.com/goharbor/harbor/src/testing/pkg/project"
reportMock "github.com/goharbor/harbor/src/testing/pkg/scan/report" reportMock "github.com/goharbor/harbor/src/testing/pkg/scan/report"
taskMock "github.com/goharbor/harbor/src/testing/pkg/task" taskMock "github.com/goharbor/harbor/src/testing/pkg/task"
@ -50,6 +52,7 @@ type ArtifactHandlerTestSuite struct {
scannerCtl scanner.Controller scannerCtl scanner.Controller
reportMgr *reportMock.Manager reportMgr *reportMock.Manager
execMgr *taskMock.ExecutionManager execMgr *taskMock.ExecutionManager
artMgr *artMock.Manager
} }
// TestArtifactHandler tests ArtifactHandler. // TestArtifactHandler tests ArtifactHandler.
@ -66,7 +69,8 @@ func (suite *ArtifactHandlerTestSuite) SetupSuite() {
suite.scannerCtl = &scannerCtlMock.Controller{} suite.scannerCtl = &scannerCtlMock.Controller{}
suite.execMgr = &taskMock.ExecutionManager{} suite.execMgr = &taskMock.ExecutionManager{}
suite.reportMgr = &reportMock.Manager{} suite.reportMgr = &reportMock.Manager{}
suite.handler = &Handler{execMgr: suite.execMgr, reportMgr: suite.reportMgr} suite.artMgr = &artMock.Manager{}
suite.handler = &Handler{execMgr: suite.execMgr, reportMgr: suite.reportMgr, artMgr: suite.artMgr}
// mock artifact // mock artifact
_, err := pkg.ArtifactMgr.Create(suite.ctx, &artifact.Artifact{ID: 1, RepositoryID: 1}) _, err := pkg.ArtifactMgr.Create(suite.ctx, &artifact.Artifact{ID: 1, RepositoryID: 1})
@ -163,6 +167,7 @@ func (suite *ArtifactHandlerTestSuite) TestOnDelete() {
suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(1)).Return(nil).Times(1) suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(1)).Return(nil).Times(1)
suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(2)).Return(nil).Times(1) suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(2)).Return(nil).Times(1)
suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(3)).Return(nil).Times(1) suite.execMgr.On("DeleteByVendor", suite.ctx, "IMAGE_SCAN", int64(3)).Return(nil).Times(1)
suite.artMgr.On("Count", suite.ctx, mock.Anything).Return(int64(0), nil).Times(3)
suite.reportMgr.On("DeleteByDigests", suite.ctx, "mock-digest", "ref-1", "ref-2").Return(nil).Times(1) suite.reportMgr.On("DeleteByDigests", suite.ctx, "mock-digest", "ref-1", "ref-2").Return(nil).Times(1)
err := suite.handler.onDelete(suite.ctx, evt) err := suite.handler.onDelete(suite.ctx, evt)
suite.Nil(err, "onDelete should return nil") suite.Nil(err, "onDelete should return nil")