mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
Move the scan overview populating logic to API handler
Move the scan overview populating logic to API handler to avoid importing cycle Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
560dd8ce7b
commit
c8c944c6e8
@ -478,6 +478,10 @@ definitions:
|
|||||||
description: The error message
|
description: The error message
|
||||||
Artifact:
|
Artifact:
|
||||||
type: object
|
type: object
|
||||||
|
x-go-type:
|
||||||
|
import:
|
||||||
|
package: "github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||||
|
type: "Artifact"
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
|
@ -31,9 +31,8 @@ import (
|
|||||||
// const definitions
|
// const definitions
|
||||||
const (
|
const (
|
||||||
// ArtifactTypeImage is the artifact type for image
|
// ArtifactTypeImage is the artifact type for image
|
||||||
ArtifactTypeImage = "IMAGE"
|
ArtifactTypeImage = "IMAGE"
|
||||||
AdditionTypeBuildHistory = "BUILD_HISTORY"
|
AdditionTypeBuildHistory = "BUILD_HISTORY"
|
||||||
AdditionTypeVulnerabilities = "VULNERABILITIES"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -129,5 +128,5 @@ func (m *manifestV2Resolver) GetArtifactType() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestV2Resolver) ListAdditionTypes() []string {
|
func (m *manifestV2Resolver) ListAdditionTypes() []string {
|
||||||
return []string{AdditionTypeBuildHistory, AdditionTypeVulnerabilities}
|
return []string{AdditionTypeBuildHistory}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ func (m *manifestV2ResolverTestSuite) TestGetArtifactType() {
|
|||||||
|
|
||||||
func (m *manifestV2ResolverTestSuite) TestListAdditionTypes() {
|
func (m *manifestV2ResolverTestSuite) TestListAdditionTypes() {
|
||||||
additions := m.resolver.ListAdditionTypes()
|
additions := m.resolver.ListAdditionTypes()
|
||||||
m.EqualValues([]string{AdditionTypeBuildHistory, AdditionTypeVulnerabilities}, additions)
|
m.EqualValues([]string{AdditionTypeBuildHistory}, additions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestManifestV2ResolverTestSuite(t *testing.T) {
|
func TestManifestV2ResolverTestSuite(t *testing.T) {
|
||||||
|
@ -19,7 +19,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver/image"
|
|
||||||
"github.com/goharbor/harbor/src/api/artifact/descriptor"
|
"github.com/goharbor/harbor/src/api/artifact/descriptor"
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
"github.com/goharbor/harbor/src/internal"
|
"github.com/goharbor/harbor/src/internal"
|
||||||
@ -83,10 +82,6 @@ type Controller interface {
|
|||||||
AddLabel(ctx context.Context, artifactID int64, labelID int64) (err error)
|
AddLabel(ctx context.Context, artifactID int64, labelID int64) (err error)
|
||||||
// RemoveLabel from the specified artifact
|
// RemoveLabel from the specified artifact
|
||||||
RemoveLabel(ctx context.Context, artifactID int64, labelID int64) (err error)
|
RemoveLabel(ctx context.Context, artifactID int64, labelID int64) (err error)
|
||||||
// TODO move this to GC controller?
|
|
||||||
// Prune removes the useless artifact records. The underlying registry data will
|
|
||||||
// be removed during garbage collection
|
|
||||||
// Prune(ctx context.Context, option *Option) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewController creates an instance of the default artifact controller
|
// NewController creates an instance of the default artifact controller
|
||||||
@ -350,14 +345,7 @@ func (c *controller) GetAddition(ctx context.Context, artifactID int64, addition
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch addition {
|
return c.abstractor.AbstractAddition(ctx, artifact, addition)
|
||||||
case image.AdditionTypeVulnerabilities:
|
|
||||||
// get the vulnerabilities from scan service
|
|
||||||
// TODO implement
|
|
||||||
return &resolver.Addition{}, nil
|
|
||||||
default:
|
|
||||||
return c.abstractor.AbstractAddition(ctx, artifact, addition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) AddLabel(ctx context.Context, artifactID int64, labelID int64) error {
|
func (c *controller) AddLabel(ctx context.Context, artifactID int64, labelID int64) error {
|
||||||
@ -382,9 +370,6 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
|||||||
if option.WithLabel {
|
if option.WithLabel {
|
||||||
c.populateLabels(ctx, artifact)
|
c.populateLabels(ctx, artifact)
|
||||||
}
|
}
|
||||||
if option.WithScanOverview {
|
|
||||||
c.populateScanOverview(ctx, artifact)
|
|
||||||
}
|
|
||||||
// populate addition links
|
// populate addition links
|
||||||
c.populateAdditionLinks(ctx, artifact)
|
c.populateAdditionLinks(ctx, artifact)
|
||||||
return artifact
|
return artifact
|
||||||
@ -471,15 +456,6 @@ func (c *controller) populateImmutableStatus(ctx context.Context, tag *Tag) {
|
|||||||
tag.Immutable = matched
|
tag.Immutable = matched
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) populateScanOverview(ctx context.Context, art *Artifact) {
|
|
||||||
// TODO implement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *controller) populateSignature(ctx context.Context, art *Artifact) {
|
|
||||||
// TODO implement
|
|
||||||
// TODO populate signature on artifact or tag level?
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
|
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
|
||||||
types, err := descriptor.ListAdditionTypes(artifact.MediaType)
|
types, err := descriptor.ListAdditionTypes(artifact.MediaType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -499,21 +475,11 @@ func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifa
|
|||||||
if artifact.AdditionLinks == nil {
|
if artifact.AdditionLinks == nil {
|
||||||
artifact.AdditionLinks = make(map[string]*AdditionLink)
|
artifact.AdditionLinks = make(map[string]*AdditionLink)
|
||||||
}
|
}
|
||||||
href := ""
|
|
||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
t = strings.ToLower(t)
|
t = strings.ToLower(t)
|
||||||
switch t {
|
|
||||||
case image.AdditionTypeVulnerabilities:
|
|
||||||
// check whether the scan service is enabled and set the addition link
|
|
||||||
// TODO implement
|
|
||||||
href = fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/vulnerabilities",
|
|
||||||
version, pro, repo, artifact.Digest)
|
|
||||||
default:
|
|
||||||
href = fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/additions/%s",
|
|
||||||
version, pro, repo, artifact.Digest, t)
|
|
||||||
}
|
|
||||||
artifact.AdditionLinks[t] = &AdditionLink{
|
artifact.AdditionLinks[t] = &AdditionLink{
|
||||||
HREF: href,
|
HREF: fmt.Sprintf("/api/%s/projects/%s/repositories/%s/artifacts/%s/additions/%s",
|
||||||
|
version, pro, repo, artifact.Digest, t),
|
||||||
Absolute: false,
|
Absolute: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,7 @@ func (c *controllerTestSuite) TestAssembleArtifact() {
|
|||||||
TagOption: &TagOption{
|
TagOption: &TagOption{
|
||||||
WithImmutableStatus: false,
|
WithImmutableStatus: false,
|
||||||
},
|
},
|
||||||
WithLabel: true,
|
WithLabel: true,
|
||||||
WithScanOverview: true,
|
|
||||||
}
|
}
|
||||||
tg := &tag.Tag{
|
tg := &tag.Tag{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
@ -259,8 +258,7 @@ func (c *controllerTestSuite) TestEnsure() {
|
|||||||
func (c *controllerTestSuite) TestList() {
|
func (c *controllerTestSuite) TestList() {
|
||||||
query := &q.Query{}
|
query := &q.Query{}
|
||||||
option := &Option{
|
option := &Option{
|
||||||
WithTag: true,
|
WithTag: true,
|
||||||
WithScanOverview: true,
|
|
||||||
}
|
}
|
||||||
c.artMgr.On("List").Return(1, []*artifact.Artifact{
|
c.artMgr.On("List").Return(1, []*artifact.Artifact{
|
||||||
{
|
{
|
||||||
|
@ -15,12 +15,10 @@
|
|||||||
package artifact
|
package artifact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/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"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Artifact is the overall view of artifact
|
// Artifact is the overall view of artifact
|
||||||
@ -29,77 +27,6 @@ type Artifact struct {
|
|||||||
Tags []*Tag // the list of tags that attached to the artifact
|
Tags []*Tag // the list of tags that attached to the artifact
|
||||||
AdditionLinks map[string]*AdditionLink // the resource link for build history(image), values.yaml(chart), dependency(chart), etc
|
AdditionLinks map[string]*AdditionLink // the resource link for build history(image), values.yaml(chart), dependency(chart), etc
|
||||||
Labels []*cmodels.Label
|
Labels []*cmodels.Label
|
||||||
// TODO add other attrs: signature, scan result, etc
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToSwagger converts the artifact to the swagger model
|
|
||||||
func (a *Artifact) ToSwagger() *models.Artifact {
|
|
||||||
art := &models.Artifact{
|
|
||||||
ID: a.ID,
|
|
||||||
Type: a.Type,
|
|
||||||
MediaType: a.MediaType,
|
|
||||||
ManifestMediaType: a.ManifestMediaType,
|
|
||||||
ProjectID: a.ProjectID,
|
|
||||||
RepositoryID: a.RepositoryID,
|
|
||||||
Digest: a.Digest,
|
|
||||||
Size: a.Size,
|
|
||||||
PullTime: strfmt.DateTime(a.PullTime),
|
|
||||||
PushTime: strfmt.DateTime(a.PushTime),
|
|
||||||
ExtraAttrs: a.ExtraAttrs,
|
|
||||||
Annotations: a.Annotations,
|
|
||||||
}
|
|
||||||
for _, reference := range a.References {
|
|
||||||
ref := &models.Reference{
|
|
||||||
ChildID: reference.ChildID,
|
|
||||||
ChildDigest: reference.ChildDigest,
|
|
||||||
ParentID: reference.ParentID,
|
|
||||||
}
|
|
||||||
if reference.Platform != nil {
|
|
||||||
ref.Platform = &models.Platform{
|
|
||||||
Architecture: reference.Platform.Architecture,
|
|
||||||
Os: reference.Platform.OS,
|
|
||||||
OsFeatures: reference.Platform.OSFeatures,
|
|
||||||
OsVersion: reference.Platform.OSVersion,
|
|
||||||
Variant: reference.Platform.Variant,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
art.References = append(art.References, ref)
|
|
||||||
}
|
|
||||||
for _, tag := range a.Tags {
|
|
||||||
art.Tags = append(art.Tags, &models.Tag{
|
|
||||||
ArtifactID: tag.ArtifactID,
|
|
||||||
ID: tag.ID,
|
|
||||||
Name: tag.Name,
|
|
||||||
PullTime: strfmt.DateTime(tag.PullTime),
|
|
||||||
PushTime: strfmt.DateTime(tag.PushTime),
|
|
||||||
RepositoryID: tag.RepositoryID,
|
|
||||||
Immutable: tag.Immutable,
|
|
||||||
Signed: tag.Signed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for addition, link := range a.AdditionLinks {
|
|
||||||
if art.AdditionLinks == nil {
|
|
||||||
art.AdditionLinks = make(map[string]models.AdditionLink)
|
|
||||||
}
|
|
||||||
art.AdditionLinks[addition] = models.AdditionLink{
|
|
||||||
Absolute: link.Absolute,
|
|
||||||
Href: link.HREF,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, label := range a.Labels {
|
|
||||||
art.Labels = append(art.Labels, &models.Label{
|
|
||||||
ID: label.ID,
|
|
||||||
Name: label.Name,
|
|
||||||
Description: label.Description,
|
|
||||||
Color: label.Color,
|
|
||||||
CreationTime: strfmt.DateTime(label.CreationTime),
|
|
||||||
ProjectID: label.ProjectID,
|
|
||||||
Scope: label.Scope,
|
|
||||||
UpdateTime: strfmt.DateTime(label.UpdateTime),
|
|
||||||
Deleted: label.Deleted,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return art
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag is the overall view of tag
|
// Tag is the overall view of tag
|
||||||
@ -107,7 +34,6 @@ type Tag struct {
|
|||||||
tag.Tag
|
tag.Tag
|
||||||
Immutable bool
|
Immutable bool
|
||||||
Signed bool
|
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
|
||||||
@ -118,10 +44,9 @@ type AdditionLink struct {
|
|||||||
|
|
||||||
// Option is used to specify the properties returned when listing/getting artifacts
|
// Option is used to specify the properties returned when listing/getting artifacts
|
||||||
type Option struct {
|
type Option struct {
|
||||||
WithTag bool
|
WithTag bool
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagOption is used to specify the properties returned when listing/getting tags
|
// TagOption is used to specify the properties returned when listing/getting tags
|
||||||
@ -130,9 +55,3 @@ type TagOption struct {
|
|||||||
WithSignature bool
|
WithSignature bool
|
||||||
SignatureChecker *signature.Checker
|
SignatureChecker *signature.Checker
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move this to GC controller?
|
|
||||||
// Option for pruning artifact records
|
|
||||||
// type Option struct {
|
|
||||||
// KeepUntagged bool // keep the untagged artifacts or not
|
|
||||||
// }
|
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/pkg/project"
|
"github.com/goharbor/harbor/src/pkg/project"
|
||||||
"github.com/goharbor/harbor/src/pkg/q"
|
"github.com/goharbor/harbor/src/pkg/q"
|
||||||
"github.com/goharbor/harbor/src/pkg/repository"
|
"github.com/goharbor/harbor/src/pkg/repository"
|
||||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||||
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/artifact"
|
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/artifact"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@ -75,7 +75,7 @@ func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListAr
|
|||||||
|
|
||||||
// set option
|
// set option
|
||||||
option := option(params.WithTag, params.WithImmutableStatus,
|
option := option(params.WithTag, params.WithImmutableStatus,
|
||||||
params.WithLabel, params.WithScanOverview, params.WithSignature)
|
params.WithLabel, params.WithSignature)
|
||||||
|
|
||||||
// list artifacts according to the query and option
|
// list artifacts according to the query and option
|
||||||
total, arts, err := a.artCtl.List(ctx, query, option)
|
total, arts, err := a.artCtl.List(ctx, query, option)
|
||||||
@ -83,9 +83,12 @@ func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListAr
|
|||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var artifacts []*models.Artifact
|
var artifacts []*model.Artifact
|
||||||
for _, art := range arts {
|
for _, art := range arts {
|
||||||
artifacts = append(artifacts, art.ToSwagger())
|
artifact := &model.Artifact{}
|
||||||
|
artifact.Artifact = *art
|
||||||
|
a.assembleArtifact(ctx, artifact, params.WithScanOverview)
|
||||||
|
artifacts = append(artifacts, artifact)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add link header
|
// TODO add link header
|
||||||
@ -98,14 +101,17 @@ func (a *artifactAPI) GetArtifact(ctx context.Context, params operation.GetArtif
|
|||||||
}
|
}
|
||||||
// set option
|
// set option
|
||||||
option := option(params.WithTag, params.WithImmutableStatus,
|
option := option(params.WithTag, params.WithImmutableStatus,
|
||||||
params.WithLabel, params.WithScanOverview, params.WithSignature)
|
params.WithLabel, params.WithSignature)
|
||||||
|
|
||||||
// get the artifact
|
// get the artifact
|
||||||
artifact, err := a.artCtl.GetByReference(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName), params.Reference, option)
|
artifact, err := a.artCtl.GetByReference(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName), params.Reference, option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
return operation.NewGetArtifactOK().WithPayload(artifact.ToSwagger())
|
art := &model.Artifact{}
|
||||||
|
art.Artifact = *artifact
|
||||||
|
a.assembleArtifact(ctx, art, params.WithScanOverview)
|
||||||
|
return operation.NewGetArtifactOK().WithPayload(art)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *artifactAPI) DeleteArtifact(ctx context.Context, params operation.DeleteArtifactParams) middleware.Responder {
|
func (a *artifactAPI) DeleteArtifact(ctx context.Context, params operation.DeleteArtifactParams) middleware.Responder {
|
||||||
@ -221,7 +227,14 @@ func (a *artifactAPI) RemoveLabel(ctx context.Context, params operation.RemoveLa
|
|||||||
return operation.NewRemoveLabelOK()
|
return operation.NewRemoveLabelOK()
|
||||||
}
|
}
|
||||||
|
|
||||||
func option(withTag, withImmutableStatus, withLabel, withScanOverview, withSignature *bool) *artifact.Option {
|
func (a *artifactAPI) assembleArtifact(ctx context.Context, artifact *model.Artifact, withScanOverview *bool) {
|
||||||
|
if withScanOverview != nil && *withScanOverview {
|
||||||
|
// TODO populate scan result
|
||||||
|
}
|
||||||
|
// TODO populate vulnerability link
|
||||||
|
}
|
||||||
|
|
||||||
|
func option(withTag, withImmutableStatus, withLabel, withSignature *bool) *artifact.Option {
|
||||||
option := &artifact.Option{
|
option := &artifact.Option{
|
||||||
WithTag: true, // return the tag by default
|
WithTag: true, // return the tag by default
|
||||||
}
|
}
|
||||||
@ -240,8 +253,5 @@ func option(withTag, withImmutableStatus, withLabel, withScanOverview, withSigna
|
|||||||
if withLabel != nil {
|
if withLabel != nil {
|
||||||
option.WithLabel = *(withLabel)
|
option.WithLabel = *(withLabel)
|
||||||
}
|
}
|
||||||
if withScanOverview != nil {
|
|
||||||
option.WithScanOverview = *(withScanOverview)
|
|
||||||
}
|
|
||||||
return option
|
return option
|
||||||
}
|
}
|
||||||
|
23
src/server/v2.0/handler/model/artifact.go
Normal file
23
src/server/v2.0/handler/model/artifact.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 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 "github.com/goharbor/harbor/src/api/artifact"
|
||||||
|
|
||||||
|
// Artifact model
|
||||||
|
type Artifact struct {
|
||||||
|
artifact.Artifact
|
||||||
|
// TODO add other properties: scan result
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user