mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 12:15:20 +01:00
Merge pull request #10745 from reasonerjt/artifact-signature-populate-v2
Artifact signature populate
This commit is contained in:
commit
560dd8ce7b
@ -563,6 +563,10 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
x-omitempty: false
|
x-omitempty: false
|
||||||
description: The immutable status of the tag
|
description: The immutable status of the tag
|
||||||
|
signed:
|
||||||
|
type: boolean
|
||||||
|
x-omitempty: false
|
||||||
|
description: The attribute indicates whether the tag is signed or not
|
||||||
ExtraAttrs:
|
ExtraAttrs:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match"
|
"github.com/goharbor/harbor/src/pkg/immutabletag/match"
|
||||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
||||||
"github.com/goharbor/harbor/src/pkg/label"
|
"github.com/goharbor/harbor/src/pkg/label"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -94,6 +95,7 @@ func NewController() Controller {
|
|||||||
repoMgr: repository.Mgr,
|
repoMgr: repository.Mgr,
|
||||||
artMgr: artifact.Mgr,
|
artMgr: artifact.Mgr,
|
||||||
tagMgr: tag.Mgr,
|
tagMgr: tag.Mgr,
|
||||||
|
sigMgr: signature.GetManager(),
|
||||||
labelMgr: label.Mgr,
|
labelMgr: label.Mgr,
|
||||||
abstractor: abstractor.NewAbstractor(),
|
abstractor: abstractor.NewAbstractor(),
|
||||||
immutableMtr: rule.NewRuleMatcher(),
|
immutableMtr: rule.NewRuleMatcher(),
|
||||||
@ -106,6 +108,7 @@ type controller struct {
|
|||||||
repoMgr repository.Manager
|
repoMgr repository.Manager
|
||||||
artMgr artifact.Manager
|
artMgr artifact.Manager
|
||||||
tagMgr tag.Manager
|
tagMgr tag.Manager
|
||||||
|
sigMgr signature.Manager
|
||||||
labelMgr label.Manager
|
labelMgr label.Manager
|
||||||
abstractor abstractor.Abstractor
|
abstractor abstractor.Abstractor
|
||||||
immutableMtr match.ImmutableTagMatcher
|
immutableMtr match.ImmutableTagMatcher
|
||||||
@ -382,9 +385,6 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
|||||||
if option.WithScanOverview {
|
if option.WithScanOverview {
|
||||||
c.populateScanOverview(ctx, artifact)
|
c.populateScanOverview(ctx, artifact)
|
||||||
}
|
}
|
||||||
if option.WithSignature {
|
|
||||||
c.populateSignature(ctx, artifact)
|
|
||||||
}
|
|
||||||
// populate addition links
|
// populate addition links
|
||||||
c.populateAdditionLinks(ctx, artifact)
|
c.populateAdditionLinks(ctx, artifact)
|
||||||
return artifact
|
return artifact
|
||||||
@ -413,12 +413,36 @@ func (c *controller) assembleTag(ctx context.Context, tag *tm.Tag, option *TagOp
|
|||||||
if option == nil {
|
if option == nil {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
repo, err := c.repoMgr.Get(ctx, tag.RepositoryID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get repo for tag: %s, error: %v", tag.Name, err)
|
||||||
|
return t
|
||||||
|
}
|
||||||
if option.WithImmutableStatus {
|
if option.WithImmutableStatus {
|
||||||
c.populateImmutableStatus(ctx, t)
|
c.populateImmutableStatus(ctx, t)
|
||||||
}
|
}
|
||||||
|
if option.WithSignature {
|
||||||
|
if a, err := c.artMgr.Get(ctx, t.ArtifactID); err != nil {
|
||||||
|
log.Errorf("Failed to get artifact for tag: %s, error: %v, skip populating signature", t.Name, err)
|
||||||
|
} else {
|
||||||
|
c.populateTagSignature(ctx, repo.Name, t, a.Digest, option)
|
||||||
|
}
|
||||||
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *controller) populateTagSignature(ctx context.Context, repo string, tag *Tag, digest string, option *TagOption) {
|
||||||
|
if option.SignatureChecker == nil {
|
||||||
|
chk, err := signature.GetManager().GetCheckerByRepo(ctx, repo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
option.SignatureChecker = chk
|
||||||
|
}
|
||||||
|
tag.Signed = option.SignatureChecker.IsTagSigned(tag.Name, digest)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
|
func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
|
||||||
labels, err := c.labelMgr.ListByArtifact(ctx, art.ID)
|
labels, err := c.labelMgr.ListByArtifact(ctx, art.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -131,7 +131,6 @@ func (c *controllerTestSuite) TestAssembleArtifact() {
|
|||||||
},
|
},
|
||||||
WithLabel: true,
|
WithLabel: true,
|
||||||
WithScanOverview: true,
|
WithScanOverview: true,
|
||||||
WithSignature: true,
|
|
||||||
}
|
}
|
||||||
tg := &tag.Tag{
|
tg := &tag.Tag{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
@ -262,7 +261,6 @@ func (c *controllerTestSuite) TestList() {
|
|||||||
option := &Option{
|
option := &Option{
|
||||||
WithTag: true,
|
WithTag: true,
|
||||||
WithScanOverview: true,
|
WithScanOverview: true,
|
||||||
WithSignature: true,
|
|
||||||
}
|
}
|
||||||
c.artMgr.On("List").Return(1, []*artifact.Artifact{
|
c.artMgr.On("List").Return(1, []*artifact.Artifact{
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
cmodels "github.com/goharbor/harbor/src/common/models"
|
cmodels "github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature"
|
||||||
"github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
"github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||||
)
|
)
|
||||||
@ -73,6 +74,7 @@ func (a *Artifact) ToSwagger() *models.Artifact {
|
|||||||
PushTime: strfmt.DateTime(tag.PushTime),
|
PushTime: strfmt.DateTime(tag.PushTime),
|
||||||
RepositoryID: tag.RepositoryID,
|
RepositoryID: tag.RepositoryID,
|
||||||
Immutable: tag.Immutable,
|
Immutable: tag.Immutable,
|
||||||
|
Signed: tag.Signed,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for addition, link := range a.AdditionLinks {
|
for addition, link := range a.AdditionLinks {
|
||||||
@ -104,7 +106,8 @@ func (a *Artifact) ToSwagger() *models.Artifact {
|
|||||||
type Tag struct {
|
type Tag struct {
|
||||||
tag.Tag
|
tag.Tag
|
||||||
Immutable bool
|
Immutable bool
|
||||||
// TODO add other attrs: signature, etc
|
Signed bool
|
||||||
|
// TODO add other attrs: label, etc
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdditionLink is a link via that the addition can be fetched
|
// AdditionLink is a link via that the addition can be fetched
|
||||||
@ -119,13 +122,13 @@ type Option struct {
|
|||||||
TagOption *TagOption // only works when WithTag is set to true
|
TagOption *TagOption // only works when WithTag is set to true
|
||||||
WithLabel bool
|
WithLabel bool
|
||||||
WithScanOverview bool
|
WithScanOverview bool
|
||||||
// TODO move it to TagOption?
|
|
||||||
WithSignature bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagOption is used to specify the properties returned when listing/getting tags
|
// TagOption is used to specify the properties returned when listing/getting tags
|
||||||
type TagOption struct {
|
type TagOption struct {
|
||||||
WithImmutableStatus bool
|
WithImmutableStatus bool
|
||||||
|
WithSignature bool
|
||||||
|
SignatureChecker *signature.Checker
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move this to GC controller?
|
// TODO move this to GC controller?
|
||||||
|
@ -17,7 +17,7 @@ package models
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/notary/model"
|
"github.com/goharbor/harbor/src/pkg/signature/notary/model"
|
||||||
"github.com/theupdateframework/notary/tuf/data"
|
"github.com/theupdateframework/notary/tuf/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,8 +34,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/common/rbac"
|
"github.com/goharbor/harbor/src/common/rbac"
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/common/utils/notary"
|
|
||||||
notarymodel "github.com/goharbor/harbor/src/common/utils/notary/model"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/registry"
|
"github.com/goharbor/harbor/src/common/utils/registry"
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
notifierEvt "github.com/goharbor/harbor/src/core/notifier/event"
|
notifierEvt "github.com/goharbor/harbor/src/core/notifier/event"
|
||||||
@ -45,6 +43,8 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
"github.com/goharbor/harbor/src/pkg/immutabletag/match/rule"
|
||||||
"github.com/goharbor/harbor/src/pkg/scan/api/scan"
|
"github.com/goharbor/harbor/src/pkg/scan/api/scan"
|
||||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature/notary"
|
||||||
|
notarymodel "github.com/goharbor/harbor/src/pkg/signature/notary/model"
|
||||||
"github.com/goharbor/harbor/src/replication"
|
"github.com/goharbor/harbor/src/replication"
|
||||||
"github.com/goharbor/harbor/src/replication/event"
|
"github.com/goharbor/harbor/src/replication/event"
|
||||||
"github.com/goharbor/harbor/src/replication/model"
|
"github.com/goharbor/harbor/src/replication/model"
|
||||||
|
@ -17,9 +17,9 @@ package contenttrust
|
|||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/common/utils/notary"
|
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/util"
|
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature/notary"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
)
|
)
|
||||||
|
@ -20,9 +20,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
notarytest "github.com/goharbor/harbor/src/common/utils/notary/test"
|
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/util"
|
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||||
|
notarytest "github.com/goharbor/harbor/src/pkg/signature/notary/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
notarytest "github.com/goharbor/harbor/src/common/utils/notary/test"
|
|
||||||
testutils "github.com/goharbor/harbor/src/common/utils/test"
|
testutils "github.com/goharbor/harbor/src/common/utils/test"
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
"github.com/goharbor/harbor/src/pkg/scan/vuln"
|
"github.com/goharbor/harbor/src/pkg/scan/vuln"
|
||||||
|
notarytest "github.com/goharbor/harbor/src/pkg/signature/notary/test"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
94
src/pkg/signature/manager.go
Normal file
94
src/pkg/signature/manager.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// 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 signature
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goharbor/harbor/src/common/security"
|
||||||
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature/notary"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature/notary/model"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Checker checks the signature status of artifact
|
||||||
|
type Checker struct {
|
||||||
|
signatures map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTagSigned checks if the tag of the artifact is signed, it also checks the signed artifact has the same digest as parm.
|
||||||
|
func (sc Checker) IsTagSigned(tag, digest string) bool {
|
||||||
|
d, ok := sc.signatures[tag]
|
||||||
|
if len(digest) == 0 {
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
return digest == d
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsArtifactSigned checks if the artifact with given digest is signed.
|
||||||
|
func (sc Checker) IsArtifactSigned(digest string) bool {
|
||||||
|
for _, v := range sc.signatures {
|
||||||
|
if v == digest {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manager interface for handling signatures of artifacts
|
||||||
|
type Manager interface {
|
||||||
|
// GetCheckerByRepo returns a Checker for checking signature
|
||||||
|
GetCheckerByRepo(ctx context.Context, repo string) (*Checker, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mgr struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCheckerByRepo ...
|
||||||
|
func (m *mgr) GetCheckerByRepo(ctx context.Context, repo string) (*Checker, error) {
|
||||||
|
if !config.WithNotary() { // return a checker that always return false
|
||||||
|
return &Checker{}, nil
|
||||||
|
}
|
||||||
|
s := make(map[string]string)
|
||||||
|
targets, err := m.getTargetsByRepo(ctx, repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, t := range targets {
|
||||||
|
if d, err := notary.DigestFromTarget(t); err != nil {
|
||||||
|
log.Warningf("Failed to get signed digest for tag %s, error: %v, skip", t.Tag, err)
|
||||||
|
} else {
|
||||||
|
s[t.Tag] = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Checker{s}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mgr) getTargetsByRepo(ctx context.Context, repo string) ([]model.Target, error) {
|
||||||
|
name := "unknown"
|
||||||
|
if sc, ok := security.FromContext(ctx); !ok || sc == nil {
|
||||||
|
log.Warningf("Unable to get security context")
|
||||||
|
} else {
|
||||||
|
name = sc.GetUsername()
|
||||||
|
}
|
||||||
|
return notary.GetInternalTargets(config.InternalNotaryEndpoint(), name, repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance = &mgr{}
|
||||||
|
|
||||||
|
// GetManager ...
|
||||||
|
func GetManager() Manager {
|
||||||
|
return instance
|
||||||
|
}
|
100
src/pkg/signature/manager_test.go
Normal file
100
src/pkg/signature/manager_test.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package signature
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goharbor/harbor/src/common"
|
||||||
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature/notary/test"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// B/C the notary requires private key for signing token, b
|
||||||
|
// before running locally, please make sure the env var is set as follow:
|
||||||
|
// export TOKEN_PRIVATE_KEY_PATH="/harbor/tests/private_key.pem"
|
||||||
|
endpoint := "10.117.4.142"
|
||||||
|
// notary-demo/busybox:1.0 is signed, more details in the notary/test pkg
|
||||||
|
notaryServer := test.NewNotaryServer(endpoint)
|
||||||
|
defer notaryServer.Close()
|
||||||
|
conf := map[string]interface{}{
|
||||||
|
common.WithNotary: "true",
|
||||||
|
common.NotaryURL: notaryServer.URL,
|
||||||
|
common.ExtEndpoint: "https://" + endpoint,
|
||||||
|
}
|
||||||
|
config.InitWithSettings(conf)
|
||||||
|
result := m.Run()
|
||||||
|
if result != 0 {
|
||||||
|
os.Exit(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCheckerByRepo(t *testing.T) {
|
||||||
|
type in struct {
|
||||||
|
repo string
|
||||||
|
tag string
|
||||||
|
digest string
|
||||||
|
}
|
||||||
|
type res struct {
|
||||||
|
tagSigned bool
|
||||||
|
artSigned bool
|
||||||
|
}
|
||||||
|
m := GetManager()
|
||||||
|
cases := []struct {
|
||||||
|
input in
|
||||||
|
expect res
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: in{
|
||||||
|
repo: "notary-demo/busybox",
|
||||||
|
tag: "1.0",
|
||||||
|
digest: "sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a7",
|
||||||
|
},
|
||||||
|
expect: res{
|
||||||
|
tagSigned: true,
|
||||||
|
artSigned: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: in{
|
||||||
|
repo: "notary-demo/busybox",
|
||||||
|
tag: "1.0",
|
||||||
|
digest: "sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a8",
|
||||||
|
},
|
||||||
|
expect: res{
|
||||||
|
tagSigned: false,
|
||||||
|
artSigned: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: in{
|
||||||
|
repo: "notary-demo/busybox",
|
||||||
|
tag: "2.0",
|
||||||
|
digest: "sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a7",
|
||||||
|
},
|
||||||
|
expect: res{
|
||||||
|
tagSigned: false,
|
||||||
|
artSigned: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: in{
|
||||||
|
repo: "non-exist",
|
||||||
|
tag: "1.0",
|
||||||
|
digest: "sha256:1359608115b94599e5641638bac5aef1ddfaa79bb96057ebf41ebc8d33acf8a7",
|
||||||
|
},
|
||||||
|
expect: res{
|
||||||
|
tagSigned: false,
|
||||||
|
artSigned: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
checker, err := m.GetCheckerByRepo(context.Background(), c.input.repo)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, c.expect.tagSigned, checker.IsTagSigned(c.input.tag, c.input.digest),
|
||||||
|
"Unexpected tagSigned value for input: %#v", c.input)
|
||||||
|
assert.Equal(t, c.expect.artSigned, checker.IsArtifactSigned(c.input.digest), "Unexpected artSigned value for input: %#v", c.input)
|
||||||
|
}
|
||||||
|
}
|
@ -17,13 +17,12 @@ package notary
|
|||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
model2 "github.com/goharbor/harbor/src/pkg/signature/notary/model"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/notary/model"
|
|
||||||
|
|
||||||
"github.com/docker/distribution/registry/auth/token"
|
"github.com/docker/distribution/registry/auth/token"
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/common/utils/registry"
|
"github.com/goharbor/harbor/src/common/utils/registry"
|
||||||
@ -54,7 +53,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetInternalTargets wraps GetTargets to read config values for getting full-qualified repo from internal notary instance.
|
// GetInternalTargets wraps GetTargets to read config values for getting full-qualified repo from internal notary instance.
|
||||||
func GetInternalTargets(notaryEndpoint string, username string, repo string) ([]model.Target, error) {
|
func GetInternalTargets(notaryEndpoint string, username string, repo string) ([]model2.Target, error) {
|
||||||
ext, err := config.ExtEndpoint()
|
ext, err := config.ExtEndpoint()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error while reading external endpoint: %v", err)
|
log.Errorf("Error while reading external endpoint: %v", err)
|
||||||
@ -68,8 +67,8 @@ func GetInternalTargets(notaryEndpoint string, username string, repo string) ([]
|
|||||||
// GetTargets is a help function called by API to fetch signature information of a given repository.
|
// GetTargets is a help function called by API to fetch signature information of a given repository.
|
||||||
// Per docker's convention the repository should contain the information of endpoint, i.e. it should look
|
// Per docker's convention the repository should contain the information of endpoint, i.e. it should look
|
||||||
// like "192.168.0.1/library/ubuntu", instead of "library/ubuntu" (fqRepo for fully-qualified repo)
|
// like "192.168.0.1/library/ubuntu", instead of "library/ubuntu" (fqRepo for fully-qualified repo)
|
||||||
func GetTargets(notaryEndpoint string, username string, fqRepo string) ([]model.Target, error) {
|
func GetTargets(notaryEndpoint string, username string, fqRepo string) ([]model2.Target, error) {
|
||||||
res := []model.Target{}
|
res := []model2.Target{}
|
||||||
t, err := tokenutil.MakeToken(username, tokenutil.Notary,
|
t, err := tokenutil.MakeToken(username, tokenutil.Notary,
|
||||||
[]*token.ResourceActions{
|
[]*token.ResourceActions{
|
||||||
{
|
{
|
||||||
@ -103,7 +102,7 @@ func GetTargets(notaryEndpoint string, username string, fqRepo string) ([]model.
|
|||||||
log.Warningf("Failed to clear cached root.json: %s, error: %v, when repo is removed from notary the signature status maybe incorrect", rootJSON, rmErr)
|
log.Warningf("Failed to clear cached root.json: %s, error: %v, when repo is removed from notary the signature status maybe incorrect", rootJSON, rmErr)
|
||||||
}
|
}
|
||||||
for _, t := range targets {
|
for _, t := range targets {
|
||||||
res = append(res, model.Target{
|
res = append(res, model2.Target{
|
||||||
Tag: t.Name,
|
Tag: t.Name,
|
||||||
Hashes: t.Hashes,
|
Hashes: t.Hashes,
|
||||||
})
|
})
|
||||||
@ -112,7 +111,7 @@ func GetTargets(notaryEndpoint string, username string, fqRepo string) ([]model.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DigestFromTarget get a target and return the value of digest, in accordance to Docker-Content-Digest
|
// DigestFromTarget get a target and return the value of digest, in accordance to Docker-Content-Digest
|
||||||
func DigestFromTarget(t model.Target) (string, error) {
|
func DigestFromTarget(t model2.Target) (string, error) {
|
||||||
sha, ok := t.Hashes["sha256"]
|
sha, ok := t.Hashes["sha256"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("no valid hash, expecting sha256")
|
return "", fmt.Errorf("no valid hash, expecting sha256")
|
@ -16,10 +16,9 @@ package notary
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
model2 "github.com/goharbor/harbor/src/pkg/signature/notary/model"
|
||||||
|
test2 "github.com/goharbor/harbor/src/pkg/signature/notary/test"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/notary/model"
|
|
||||||
|
|
||||||
notarytest "github.com/goharbor/harbor/src/common/utils/notary/test"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils/test"
|
"github.com/goharbor/harbor/src/common/utils/test"
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -36,7 +35,7 @@ var endpoint = "10.117.4.142"
|
|||||||
var notaryServer *httptest.Server
|
var notaryServer *httptest.Server
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
notaryServer = notarytest.NewNotaryServer(endpoint)
|
notaryServer = test2.NewNotaryServer(endpoint)
|
||||||
defer notaryServer.Close()
|
defer notaryServer.Close()
|
||||||
var defaultConfig = map[string]interface{}{
|
var defaultConfig = map[string]interface{}{
|
||||||
common.ExtEndpoint: "https://" + endpoint,
|
common.ExtEndpoint: "https://" + endpoint,
|
||||||
@ -80,13 +79,13 @@ func TestGetDigestFromTarget(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
var t1 model.Target
|
var t1 model2.Target
|
||||||
err := json.Unmarshal([]byte(str), &t1)
|
err := json.Unmarshal([]byte(str), &t1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
hash2 := make(map[string][]byte)
|
hash2 := make(map[string][]byte)
|
||||||
t2 := model.Target{
|
t2 := model2.Target{
|
||||||
Tag: "2.0",
|
Tag: "2.0",
|
||||||
Hashes: hash2,
|
Hashes: hash2,
|
||||||
}
|
}
|
@ -2,10 +2,10 @@ package contenttrust
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
"github.com/goharbor/harbor/src/common/utils/notary"
|
|
||||||
"github.com/goharbor/harbor/src/core/config"
|
"github.com/goharbor/harbor/src/core/config"
|
||||||
"github.com/goharbor/harbor/src/core/middlewares/util"
|
"github.com/goharbor/harbor/src/core/middlewares/util"
|
||||||
internal_errors "github.com/goharbor/harbor/src/internal/error"
|
internal_errors "github.com/goharbor/harbor/src/internal/error"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/signature/notary"
|
||||||
serror "github.com/goharbor/harbor/src/server/error"
|
serror "github.com/goharbor/harbor/src/server/error"
|
||||||
"github.com/goharbor/harbor/src/server/middleware"
|
"github.com/goharbor/harbor/src/server/middleware"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -229,10 +229,12 @@ func option(withTag, withImmutableStatus, withLabel, withScanOverview, withSigna
|
|||||||
option.WithTag = *(withTag)
|
option.WithTag = *(withTag)
|
||||||
}
|
}
|
||||||
if option.WithTag {
|
if option.WithTag {
|
||||||
|
option.TagOption = &artifact.TagOption{}
|
||||||
if withImmutableStatus != nil {
|
if withImmutableStatus != nil {
|
||||||
option.TagOption = &artifact.TagOption{
|
option.TagOption.WithImmutableStatus = *(withImmutableStatus)
|
||||||
WithImmutableStatus: *(withImmutableStatus),
|
}
|
||||||
}
|
if withSignature != nil {
|
||||||
|
option.TagOption.WithSignature = *withSignature
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if withLabel != nil {
|
if withLabel != nil {
|
||||||
@ -241,8 +243,5 @@ func option(withTag, withImmutableStatus, withLabel, withScanOverview, withSigna
|
|||||||
if withScanOverview != nil {
|
if withScanOverview != nil {
|
||||||
option.WithScanOverview = *(withScanOverview)
|
option.WithScanOverview = *(withScanOverview)
|
||||||
}
|
}
|
||||||
if withSignature != nil {
|
|
||||||
option.WithSignature = *(withSignature)
|
|
||||||
}
|
|
||||||
return option
|
return option
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user