From 0b4f98074e515125a70c7652fbb288771d5a1614 Mon Sep 17 00:00:00 2001 From: Wang Yan Date: Mon, 17 Jan 2022 19:09:56 +0800 Subject: [PATCH] fix cosign conflict error on landing data (#16228) Cosign client will generate the same signature to the same manifest, ignore the conflict error in middleware Signed-off-by: Wang Yan --- src/server/middleware/cosign/cosign.go | 24 +++++--- src/server/middleware/cosign/cosign_test.go | 67 +++++++++++++++++++++ 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/server/middleware/cosign/cosign.go b/src/server/middleware/cosign/cosign.go index 8aeb986b7..d454956cf 100644 --- a/src/server/middleware/cosign/cosign.go +++ b/src/server/middleware/cosign/cosign.go @@ -1,12 +1,14 @@ package cosign import ( + "context" "fmt" "github.com/docker/distribution/reference" "github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/lib" "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/pkg/accessory" "github.com/goharbor/harbor/src/pkg/accessory/model" "github.com/goharbor/harbor/src/pkg/distribution" @@ -104,16 +106,20 @@ func CosignSignatureMiddleware() func(http.Handler) http.Handler { return err } - _, err = accessory.Mgr.Create(ctx, model.AccessoryData{ - ArtifactID: art.ID, - SubArtifactID: subjectArt.ID, - Size: desc.Size, - Digest: desc.Digest.String(), - Type: model.TypeCosignSignature, - }) - if err != nil { - logger.Errorf("failed to get cosign signature artifact: %s, error: %v", desc.Digest.String(), err) + if err := orm.WithTransaction(func(ctx context.Context) error { + _, err := accessory.Mgr.Create(ctx, model.AccessoryData{ + ArtifactID: art.ID, + SubArtifactID: subjectArt.ID, + Size: desc.Size, + Digest: desc.Digest.String(), + Type: model.TypeCosignSignature, + }) return err + })(orm.SetTransactionOpNameToContext(ctx, "tx-create-cosign-accessory")); err != nil { + if !errors.IsConflictErr(err) { + logger.Errorf("failed to create cosign signature artifact: %s, error: %v", desc.Digest.String(), err) + return err + } } } diff --git a/src/server/middleware/cosign/cosign_test.go b/src/server/middleware/cosign/cosign_test.go index 2916d4423..a24ec8bbc 100644 --- a/src/server/middleware/cosign/cosign_test.go +++ b/src/server/middleware/cosign/cosign_test.go @@ -7,6 +7,7 @@ import ( "github.com/goharbor/harbor/src/lib/q" "github.com/goharbor/harbor/src/pkg/accessory" "github.com/goharbor/harbor/src/pkg/accessory/model" + accessorymodel "github.com/goharbor/harbor/src/pkg/accessory/model" "github.com/goharbor/harbor/src/pkg/artifact" "github.com/goharbor/harbor/src/pkg/distribution" htesting "github.com/goharbor/harbor/src/testing" @@ -81,6 +82,44 @@ func (suite *MiddlewareTestSuite) addArt(pid, repositoryID int64, repositoryName return afid } +func (suite *MiddlewareTestSuite) addArtAcc(pid, repositoryID int64, repositoryName, dgt, accdgt string) int64 { + subaf := &artifact.Artifact{ + Type: "Docker-Image", + ProjectID: pid, + RepositoryID: repositoryID, + RepositoryName: repositoryName, + Digest: dgt, + Size: 1024, + PushTime: time.Now(), + PullTime: time.Now(), + } + subafid, err := artifact.Mgr.Create(suite.Context(), subaf) + suite.Nil(err, fmt.Sprintf("Add artifact failed for %d", repositoryID)) + + af := &artifact.Artifact{ + Type: "Cosign", + ProjectID: pid, + RepositoryID: repositoryID, + RepositoryName: repositoryName, + Digest: accdgt, + Size: 1024, + PushTime: time.Now(), + PullTime: time.Now(), + } + afid, err := artifact.Mgr.Create(suite.Context(), af) + suite.Nil(err, fmt.Sprintf("Add artifact failed for %d", repositoryID)) + + accid, err := accessory.Mgr.Create(suite.Context(), accessorymodel.AccessoryData{ + ID: 1, + ArtifactID: afid, + SubArtifactID: subafid, + Digest: accdgt, + Type: accessorymodel.TypeCosignSignature, + }) + suite.Nil(err, fmt.Sprintf("Add artifact accesspry failed for %d", repositoryID)) + return accid +} + func (suite *MiddlewareTestSuite) TestCosignSignature() { suite.WithProject(func(projectID int64, projectName string) { name := fmt.Sprintf("%s/hello-world", projectName) @@ -112,6 +151,34 @@ func (suite *MiddlewareTestSuite) TestCosignSignature() { }) } +func (suite *MiddlewareTestSuite) TestCosignSignatureDup() { + suite.WithProject(func(projectID int64, projectName string) { + name := fmt.Sprintf("%s/hello-world", projectName) + subArtDigest := suite.DigestString() + ref := fmt.Sprintf("%s.sig", strings.ReplaceAll(subArtDigest, "sha256:", "sha256-")) + _, descriptor, req := suite.prepare(name, ref) + + _, repoId, err := repository.Ctl.Ensure(suite.Context(), name) + suite.Nil(err) + accID := suite.addArtAcc(projectID, repoId, name, subArtDigest, descriptor.Digest.String()) + + res := httptest.NewRecorder() + next := suite.NextHandler(http.StatusCreated, map[string]string{"Docker-Content-Digest": descriptor.Digest.String()}) + CosignSignatureMiddleware()(next).ServeHTTP(res, req) + suite.Equal(http.StatusCreated, res.Code) + + accs, err := accessory.Mgr.List(suite.Context(), &q.Query{ + Keywords: map[string]interface{}{ + "ID": accID, + }, + }) + suite.Equal(1, len(accs)) + suite.Equal(descriptor.Digest.String(), accs[0].GetData().Digest) + suite.True(accs[0].IsHard()) + suite.Equal(model.TypeCosignSignature, accs[0].GetData().Type) + }) +} + func (suite *MiddlewareTestSuite) TestMatchManifestURLPattern() { _, _, ok := matchCosignSignaturePattern("/v2/library/hello-world/manifests/.Invalid") suite.False(ok)