mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-27 13:02:59 +02:00
Merge branch 'main' into Support-relativeurls-in-harbor-config
This commit is contained in:
commit
e791c143d0
@ -1192,6 +1192,8 @@ paths:
|
||||
$ref: '#/responses/403'
|
||||
'404':
|
||||
$ref: '#/responses/404'
|
||||
'422':
|
||||
$ref: '#/responses/422'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/projects/{project_name}/repositories/{repository_name}/artifacts/{reference}/scan/stop:
|
||||
@ -1223,6 +1225,8 @@ paths:
|
||||
$ref: '#/responses/403'
|
||||
'404':
|
||||
$ref: '#/responses/404'
|
||||
'422':
|
||||
$ref: '#/responses/422'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/projects/{project_name}/repositories/{repository_name}/artifacts/{reference}/scan/{report_id}/log:
|
||||
@ -1476,6 +1480,8 @@ paths:
|
||||
$ref: '#/responses/403'
|
||||
'404':
|
||||
$ref: '#/responses/404'
|
||||
'422':
|
||||
$ref: '#/responses/422'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/projects/{project_name}/repositories/{repository_name}/artifacts/{reference}/labels:
|
||||
@ -4823,6 +4829,8 @@ paths:
|
||||
$ref: '#/responses/403'
|
||||
'404':
|
||||
$ref: '#/responses/404'
|
||||
'422':
|
||||
$ref: '#/responses/422'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/schedules:
|
||||
@ -6456,6 +6464,14 @@ responses:
|
||||
type: string
|
||||
schema:
|
||||
$ref: '#/definitions/Errors'
|
||||
'422':
|
||||
description: Unsupported Type
|
||||
headers:
|
||||
X-Request-Id:
|
||||
description: The ID of the corresponding request for the response
|
||||
type: string
|
||||
schema:
|
||||
$ref: '#/definitions/Errors'
|
||||
'500':
|
||||
description: Internal server error
|
||||
headers:
|
||||
@ -6800,6 +6816,8 @@ definitions:
|
||||
format: int64
|
||||
description: 'Time in seconds required to create the report'
|
||||
example: 300
|
||||
scanner:
|
||||
$ref: '#/definitions/Scanner'
|
||||
NativeReportSummary:
|
||||
type: object
|
||||
description: 'The summary for the native report'
|
||||
|
@ -326,12 +326,6 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot, isAcces
|
||||
return err
|
||||
}
|
||||
|
||||
if isAccessory {
|
||||
if err := c.accessoryMgr.DeleteAccessories(ctx, q.New(q.KeyWords{"ArtifactID": art.ID, "Digest": art.Digest})); err != nil && !errors.IsErr(err, errors.NotFoundCode) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// the child artifact is referenced by some tags, skip
|
||||
if !isRoot && len(art.Tags) > 0 {
|
||||
return nil
|
||||
@ -354,6 +348,12 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot, isAcces
|
||||
return nil
|
||||
}
|
||||
|
||||
if isAccessory {
|
||||
if err := c.accessoryMgr.DeleteAccessories(ctx, q.New(q.KeyWords{"ArtifactID": art.ID, "Digest": art.Digest})); err != nil && !errors.IsErr(err, errors.NotFoundCode) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// delete accessories if contains any
|
||||
for _, acc := range art.Accessories {
|
||||
// only hard ref accessory should be removed
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/artifact"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/sbom"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/event/operator"
|
||||
"github.com/goharbor/harbor/src/controller/repository"
|
||||
@ -36,6 +37,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/pkg"
|
||||
pkgArt "github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/scan/report"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
"github.com/goharbor/harbor/src/pkg/task"
|
||||
)
|
||||
|
||||
@ -319,6 +321,11 @@ func (a *ArtifactEventHandler) onDelete(ctx context.Context, event *event.Artifa
|
||||
log.Errorf("failed to delete scan reports of artifact %v, error: %v", unrefDigests, err)
|
||||
}
|
||||
|
||||
if event.Artifact.Type == sbom.ArtifactTypeSBOM && len(event.Artifact.Digest) > 0 {
|
||||
if err := reportMgr.DeleteByExtraAttr(ctx, v1.MimeTypeSBOMReport, "sbom_digest", event.Artifact.Digest); err != nil {
|
||||
log.Errorf("failed to delete scan reports of with sbom digest %v, error: %v", event.Artifact.Digest, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/controller/artifact"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/event/handler/util"
|
||||
eventModel "github.com/goharbor/harbor/src/controller/event/model"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/controller/scan"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
@ -104,6 +105,9 @@ func constructScanImagePayload(ctx context.Context, event *event.ScanImageEvent,
|
||||
RepoFullName: event.Artifact.Repository,
|
||||
RepoType: repoType,
|
||||
},
|
||||
Scan: &eventModel.Scan{
|
||||
ScanType: event.ScanType,
|
||||
},
|
||||
},
|
||||
Operator: event.Operator,
|
||||
}
|
||||
@ -138,17 +142,29 @@ func constructScanImagePayload(ctx context.Context, event *event.ScanImageEvent,
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
// Add scan overview
|
||||
summaries, err := scan.DefaultController.GetSummary(ctx, art, []string{v1.MimeTypeNativeReport, v1.MimeTypeGenericVulnerabilityReport})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "construct scan payload")
|
||||
scanSummaries := map[string]interface{}{}
|
||||
if event.ScanType == v1.ScanTypeVulnerability {
|
||||
scanSummaries, err = scan.DefaultController.GetSummary(ctx, art, []string{v1.MimeTypeNativeReport, v1.MimeTypeGenericVulnerabilityReport})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "construct scan payload")
|
||||
}
|
||||
}
|
||||
|
||||
sbomOverview := map[string]interface{}{}
|
||||
if event.ScanType == v1.ScanTypeSbom {
|
||||
sbomOverview, err = scan.DefaultController.GetSummary(ctx, art, []string{v1.MimeTypeSBOMReport})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "construct scan payload")
|
||||
}
|
||||
}
|
||||
|
||||
// Add scan overview and sbom overview
|
||||
resource := &model.Resource{
|
||||
Tag: event.Artifact.Tag,
|
||||
Digest: event.Artifact.Digest,
|
||||
ResourceURL: resURL,
|
||||
ScanOverview: summaries,
|
||||
ScanOverview: scanSummaries,
|
||||
SBOMOverview: sbomOverview,
|
||||
}
|
||||
payload.EventData.Resources = append(payload.EventData.Resources, resource)
|
||||
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
// ScanImageMetaData defines meta data of image scanning event
|
||||
type ScanImageMetaData struct {
|
||||
Artifact *v1.Artifact
|
||||
ScanType string
|
||||
Status string
|
||||
Operator string
|
||||
}
|
||||
@ -55,6 +56,7 @@ func (si *ScanImageMetaData) Resolve(evt *event.Event) error {
|
||||
Artifact: si.Artifact,
|
||||
OccurAt: time.Now(),
|
||||
Operator: si.Operator,
|
||||
ScanType: si.ScanType,
|
||||
}
|
||||
|
||||
evt.Topic = topic
|
||||
|
@ -74,3 +74,9 @@ type RetentionRule struct {
|
||||
// Selector attached to the rule for filtering scope (e.g: repositories or namespaces)
|
||||
ScopeSelectors map[string][]*rule.Selector `json:"scope_selectors,omitempty"`
|
||||
}
|
||||
|
||||
// Scan describes scan infos
|
||||
type Scan struct {
|
||||
// ScanType the scan type
|
||||
ScanType string `json:"scan_type,omitempty"`
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func (p *PushArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
|
||||
ResourceType: "artifact"}
|
||||
|
||||
if len(p.Tags) == 0 {
|
||||
auditLog.Resource = fmt.Sprintf("%s:%s",
|
||||
auditLog.Resource = fmt.Sprintf("%s@%s",
|
||||
p.Artifact.RepositoryName, p.Artifact.Digest)
|
||||
} else {
|
||||
auditLog.Resource = fmt.Sprintf("%s:%s",
|
||||
@ -222,7 +222,7 @@ func (d *DeleteArtifactEvent) ResolveToAuditLog() (*model.AuditLog, error) {
|
||||
Operation: rbac.ActionDelete.String(),
|
||||
Username: d.Operator,
|
||||
ResourceType: "artifact",
|
||||
Resource: fmt.Sprintf("%s:%s", d.Artifact.RepositoryName, d.Artifact.Digest)}
|
||||
Resource: fmt.Sprintf("%s@%s", d.Artifact.RepositoryName, d.Artifact.Digest)}
|
||||
return auditLog, nil
|
||||
}
|
||||
|
||||
@ -289,6 +289,7 @@ func (d *DeleteTagEvent) String() string {
|
||||
// ScanImageEvent is scanning image related event data to publish
|
||||
type ScanImageEvent struct {
|
||||
EventType string
|
||||
ScanType string
|
||||
Artifact *v1.Artifact
|
||||
OccurAt time.Time
|
||||
Operator string
|
||||
|
@ -751,13 +751,34 @@ func (bc *basicController) GetSBOMSummary(ctx context.Context, art *ar.Artifact,
|
||||
reportContent := reports[0].Report
|
||||
result := map[string]interface{}{}
|
||||
if len(reportContent) == 0 {
|
||||
log.Warning("no content for current report")
|
||||
status := bc.retrieveStatusFromTask(ctx, reports[0].UUID)
|
||||
if len(status) > 0 {
|
||||
result[sbomModel.ReportID] = reports[0].UUID
|
||||
result[sbomModel.ScanStatus] = status
|
||||
}
|
||||
log.Debug("no content for current report")
|
||||
return result, nil
|
||||
}
|
||||
err = json.Unmarshal([]byte(reportContent), &result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// retrieve the status from task
|
||||
func (bc *basicController) retrieveStatusFromTask(ctx context.Context, reportID string) string {
|
||||
if len(reportID) == 0 {
|
||||
return ""
|
||||
}
|
||||
tasks, err := bc.taskMgr.ListScanTasksByReportUUID(ctx, reportID)
|
||||
if err != nil {
|
||||
log.Warningf("can not find the task with report UUID %v, error %v", reportID, err)
|
||||
return ""
|
||||
}
|
||||
if len(tasks) > 0 {
|
||||
return tasks[0].Status
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetScanLog ...
|
||||
func (bc *basicController) GetScanLog(ctx context.Context, artifact *ar.Artifact, uuid string) ([]byte, error) {
|
||||
if len(uuid) == 0 {
|
||||
|
@ -70,9 +70,10 @@ type ControllerTestSuite struct {
|
||||
|
||||
tagCtl *tagtesting.FakeController
|
||||
|
||||
registration *scanner.Registration
|
||||
artifact *artifact.Artifact
|
||||
rawReport string
|
||||
registration *scanner.Registration
|
||||
artifact *artifact.Artifact
|
||||
wrongArtifact *artifact.Artifact
|
||||
rawReport string
|
||||
|
||||
execMgr *tasktesting.ExecutionManager
|
||||
taskMgr *tasktesting.Manager
|
||||
@ -101,6 +102,9 @@ func (suite *ControllerTestSuite) SetupSuite() {
|
||||
suite.artifact.Digest = "digest-code"
|
||||
suite.artifact.ManifestMediaType = v1.MimeTypeDockerArtifact
|
||||
|
||||
suite.wrongArtifact = &artifact.Artifact{Artifact: art.Artifact{ID: 2, ProjectID: 1}}
|
||||
suite.wrongArtifact.Digest = "digest-wrong"
|
||||
|
||||
m := &v1.ScannerAdapterMetadata{
|
||||
Scanner: &v1.Scanner{
|
||||
Name: "Trivy",
|
||||
@ -202,8 +206,11 @@ func (suite *ControllerTestSuite) SetupSuite() {
|
||||
Report: `{"sbom_digest": "sha256:1234567890", "scan_status": "Success", "duration": 3, "start_time": "2021-09-01T00:00:00Z", "end_time": "2021-09-01T00:00:03Z"}`,
|
||||
},
|
||||
}
|
||||
|
||||
emptySBOMReport := []*scan.Report{{Report: ``, UUID: "rp-uuid-004"}}
|
||||
mgr.On("GetBy", mock.Anything, suite.artifact.Digest, suite.registration.UUID, []string{v1.MimeTypeNativeReport}).Return(reports, nil)
|
||||
mgr.On("GetBy", mock.Anything, suite.artifact.Digest, suite.registration.UUID, []string{v1.MimeTypeSBOMReport}).Return(sbomReport, nil)
|
||||
mgr.On("GetBy", mock.Anything, suite.wrongArtifact.Digest, suite.registration.UUID, []string{v1.MimeTypeSBOMReport}).Return(emptySBOMReport, nil)
|
||||
mgr.On("Get", mock.Anything, "rp-uuid-001").Return(reports[0], nil)
|
||||
mgr.On("UpdateReportData", "rp-uuid-001", suite.rawReport, (int64)(10000)).Return(nil)
|
||||
mgr.On("UpdateStatus", "the-uuid-123", "Success", (int64)(10000)).Return(nil)
|
||||
@ -654,6 +661,12 @@ func (suite *ControllerTestSuite) TestGenerateSBOMSummary() {
|
||||
suite.NotNil(dgst)
|
||||
suite.Equal("Success", status)
|
||||
suite.Equal("sha256:1234567890", dgst)
|
||||
tasks := []*task.Task{{Status: "Error"}}
|
||||
suite.taskMgr.On("ListScanTasksByReportUUID", mock.Anything, "rp-uuid-004").Return(tasks, nil).Once()
|
||||
sum2, err := suite.c.GetSummary(context.TODO(), suite.wrongArtifact, []string{v1.MimeTypeSBOMReport})
|
||||
suite.Nil(err)
|
||||
suite.NotNil(sum2)
|
||||
|
||||
}
|
||||
|
||||
func TestIsSBOMMimeTypes(t *testing.T) {
|
||||
@ -683,5 +696,11 @@ func (suite *ControllerTestSuite) TestDeleteArtifactAccessories() {
|
||||
}
|
||||
ctx := orm.NewContext(nil, &ormtesting.FakeOrmer{})
|
||||
suite.NoError(suite.c.deleteArtifactAccessories(ctx, reports))
|
||||
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestRetrieveStatusFromTask() {
|
||||
tasks := []*task.Task{{Status: "Error"}}
|
||||
suite.taskMgr.On("ListScanTasksByReportUUID", mock.Anything, "rp-uuid-004").Return(tasks, nil).Once()
|
||||
status := suite.c.retrieveStatusFromTask(nil, "rp-uuid-004")
|
||||
suite.Equal("Error", status)
|
||||
}
|
||||
|
@ -120,6 +120,13 @@ func scanTaskStatusChange(ctx context.Context, taskID int64, status string) (err
|
||||
if operator, ok := exec.ExtraAttrs["operator"].(string); ok {
|
||||
e.Operator = operator
|
||||
}
|
||||
|
||||
// extract ScanType if exist in ExtraAttrs
|
||||
if c, ok := exec.ExtraAttrs["enabled_capabilities"].(map[string]interface{}); ok {
|
||||
if Type, ok := c["type"].(string); ok {
|
||||
e.ScanType = Type
|
||||
}
|
||||
}
|
||||
// fire event
|
||||
notification.AddEvent(ctx, e)
|
||||
}
|
||||
|
27
src/go.mod
27
src/go.mod
@ -12,7 +12,7 @@ require (
|
||||
github.com/beego/i18n v0.0.0-20140604031826-e87155e8f0c0
|
||||
github.com/bmatcuk/doublestar v1.3.4
|
||||
github.com/casbin/casbin v1.9.1
|
||||
github.com/cenkalti/backoff/v4 v4.2.1
|
||||
github.com/cenkalti/backoff/v4 v4.3.0
|
||||
github.com/cloudevents/sdk-go/v2 v2.15.2
|
||||
github.com/coreos/go-oidc/v3 v3.10.0
|
||||
github.com/dghubble/sling v1.1.0
|
||||
@ -31,7 +31,7 @@ require (
|
||||
github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8
|
||||
github.com/gocraft/work v0.5.1
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0
|
||||
github.com/golang-migrate/migrate/v4 v4.16.2
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/google/go-containerregistry v0.19.0
|
||||
github.com/google/uuid v1.6.0
|
||||
@ -51,20 +51,20 @@ require (
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/volcengine/volcengine-go-sdk v1.0.97
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.1
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0
|
||||
go.opentelemetry.io/otel v1.24.0
|
||||
go.opentelemetry.io/otel v1.26.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.0.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0
|
||||
go.opentelemetry.io/otel/sdk v1.24.0
|
||||
go.opentelemetry.io/otel/trace v1.24.0
|
||||
go.opentelemetry.io/otel/sdk v1.26.0
|
||||
go.opentelemetry.io/otel/trace v1.26.0
|
||||
go.uber.org/ratelimit v0.3.1
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/net v0.22.0
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/oauth2 v0.19.0
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/text v0.14.0
|
||||
@ -136,6 +136,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.16.5 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
@ -159,21 +160,21 @@ require (
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/vbatts/tar-split v0.11.3 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.23 // indirect
|
||||
go.mongodb.org/mongo-driver v1.13.1 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.26.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.19.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/term v0.18.0 // indirect
|
||||
google.golang.org/api v0.149.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/term v0.19.0 // indirect
|
||||
google.golang.org/api v0.150.0 // indirect
|
||||
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||
|
58
src/go.sum
58
src/go.sum
@ -96,8 +96,8 @@ github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQ
|
||||
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
|
||||
github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=
|
||||
github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
@ -130,8 +130,8 @@ github.com/dghubble/sling v1.1.0/go.mod h1:ZcPRuLm0qrcULW2gOrjXrAWgf76sahqSyxXyV
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dhui/dktest v0.3.16 h1:i6gq2YQEtcrjKbeJpBkWjE8MmLZPYllcjOFbTZuPDnw=
|
||||
github.com/dhui/dktest v0.3.16/go.mod h1:gYaA3LRmM8Z4vJl2MA0THIigJoZrwOansEOsp+kqxp0=
|
||||
github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg=
|
||||
github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA=
|
||||
github.com/distribution/distribution v2.8.2+incompatible h1:k9+4DKdOG+quPFZXT/mUsiQrGu9vYCp+dXpuPkuqhk8=
|
||||
github.com/distribution/distribution v2.8.2+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
@ -240,8 +240,8 @@ github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQA
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-migrate/migrate/v4 v4.16.2 h1:8coYbMKUyInrFk1lfGfRovTLAW7PhWp8qQDT2iKfuoA=
|
||||
github.com/golang-migrate/migrate/v4 v4.16.2/go.mod h1:pfcJX4nPHaVdc5nmdCikFBWtm+UBpiZjRNNsyBbp0/o=
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@ -592,8 +592,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@ -603,8 +604,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.233+incompatible h1:q+D/Y9jla3afgsIihtyhwyl0c2W+eRWNM9ohVwPiiPw=
|
||||
@ -646,22 +647,22 @@ go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
|
||||
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
|
||||
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.0.0 h1:cLhx8llHw02h5JTqGqaRbYn+QVKHmrzD9vEbKnSPk5U=
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.0.0/go.mod h1:q10N1AolE1JjqKrFJK2tYw0iZpmX+HBaXBtuCzRnBGQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
|
||||
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
|
||||
go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
|
||||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
|
||||
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
|
||||
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
|
||||
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
|
||||
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
|
||||
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
|
||||
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
@ -702,9 +703,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -730,8 +730,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -758,8 +758,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -817,18 +817,16 @@ golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
@ -77,8 +77,8 @@ const (
|
||||
// TypeSubject ...
|
||||
TypeSubject = "subject.accessory"
|
||||
|
||||
// TypeHarborSBOM identifies harbor.sbom
|
||||
TypeHarborSBOM = "harbor.sbom"
|
||||
// TypeHarborSBOM identifies sbom.harbor
|
||||
TypeHarborSBOM = "sbom.harbor"
|
||||
)
|
||||
|
||||
// AccessoryData ...
|
||||
|
@ -42,6 +42,7 @@ type EventData struct {
|
||||
Repository *Repository `json:"repository,omitempty"`
|
||||
Replication *model.Replication `json:"replication,omitempty"`
|
||||
Retention *model.Retention `json:"retention,omitempty"`
|
||||
Scan *model.Scan `json:"scan,omitempty"`
|
||||
Custom map[string]string `json:"custom_attributes,omitempty"`
|
||||
}
|
||||
|
||||
@ -51,6 +52,7 @@ type Resource struct {
|
||||
Tag string `json:"tag,omitempty"`
|
||||
ResourceURL string `json:"resource_url,omitempty"`
|
||||
ScanOverview map[string]interface{} `json:"scan_overview,omitempty"`
|
||||
SBOMOverview map[string]interface{} `json:"sbom_overview,omitempty"`
|
||||
}
|
||||
|
||||
// Repository info of notification event
|
||||
|
@ -8,15 +8,16 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
adp "github.com/goharbor/harbor/src/pkg/reg/adapter"
|
||||
"github.com/goharbor/harbor/src/pkg/reg/adapter/native"
|
||||
"github.com/goharbor/harbor/src/pkg/reg/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
volcCR "github.com/volcengine/volcengine-go-sdk/service/cr"
|
||||
"github.com/volcengine/volcengine-go-sdk/volcengine"
|
||||
"github.com/volcengine/volcengine-go-sdk/volcengine/credentials"
|
||||
volcSession "github.com/volcengine/volcengine-go-sdk/volcengine/session"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
adp "github.com/goharbor/harbor/src/pkg/reg/adapter"
|
||||
"github.com/goharbor/harbor/src/pkg/reg/adapter/native"
|
||||
"github.com/goharbor/harbor/src/pkg/reg/model"
|
||||
)
|
||||
|
||||
func getMockAdapter_withoutCred(t *testing.T, hasCred, health bool) (*adapter, *httptest.Server) {
|
||||
@ -94,16 +95,17 @@ func TestAdapter_NewAdapter_InvalidURL(t *testing.T) {
|
||||
assert.Nil(t, adapter)
|
||||
}
|
||||
|
||||
func TestAdapter_NewAdapter_PingFailed(t *testing.T) {
|
||||
factory, _ := adp.GetFactory(model.RegistryTypeVolcCR)
|
||||
adapter, err := factory.Create(&model.Registry{
|
||||
Type: model.RegistryTypeVolcCR,
|
||||
Credential: &model.Credential{},
|
||||
URL: "https://cr-test-cn-beijing.cr.volces.com",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, adapter)
|
||||
}
|
||||
// remove it because failed
|
||||
// func TestAdapter_NewAdapter_PingFailed(t *testing.T) {
|
||||
// factory, _ := adp.GetFactory(model.RegistryTypeVolcCR)
|
||||
// adapter, err := factory.Create(&model.Registry{
|
||||
// Type: model.RegistryTypeVolcCR,
|
||||
// Credential: &model.Credential{},
|
||||
// URL: "https://cr-test-cn-beijing.cr.volces.com",
|
||||
// })
|
||||
// assert.Error(t, err)
|
||||
// assert.Nil(t, adapter)
|
||||
// }
|
||||
|
||||
func TestAdapter_Info(t *testing.T) {
|
||||
a, s := getMockAdapter_withoutCred(t, true, true)
|
||||
|
@ -16,6 +16,7 @@ package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
@ -38,6 +39,8 @@ type DAO interface {
|
||||
UpdateReportData(ctx context.Context, uuid string, report string) error
|
||||
// Update update report
|
||||
Update(ctx context.Context, r *Report, cols ...string) error
|
||||
// DeleteByExtraAttr delete the scan_report by mimeType and extra attribute
|
||||
DeleteByExtraAttr(ctx context.Context, mimeType, attrName, attrValue string) error
|
||||
}
|
||||
|
||||
// New returns an instance of the default DAO
|
||||
@ -110,3 +113,14 @@ func (d *dao) Update(ctx context.Context, r *Report, cols ...string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dao) DeleteByExtraAttr(ctx context.Context, mimeType, attrName, attrValue string) error {
|
||||
o, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delReportSQL := "delete from scan_report where mime_type = ? and report::jsonb @> ?"
|
||||
dgstJSONStr := fmt.Sprintf(`{"%s":"%s"}`, attrName, attrValue)
|
||||
_, err = o.Raw(delReportSQL, mimeType, dgstJSONStr).Exec()
|
||||
return err
|
||||
}
|
||||
|
@ -53,14 +53,23 @@ func (suite *ReportTestSuite) SetupTest() {
|
||||
RegistrationUUID: "ruuid",
|
||||
MimeType: v1.MimeTypeNativeReport,
|
||||
}
|
||||
|
||||
suite.create(r)
|
||||
sbomReport := &Report{
|
||||
UUID: "uuid3",
|
||||
Digest: "digest1003",
|
||||
RegistrationUUID: "ruuid",
|
||||
MimeType: v1.MimeTypeSBOMReport,
|
||||
Report: `{"sbom_digest": "sha256:abc"}`,
|
||||
}
|
||||
suite.create(sbomReport)
|
||||
}
|
||||
|
||||
// TearDownTest clears enf for test case.
|
||||
func (suite *ReportTestSuite) TearDownTest() {
|
||||
_, err := suite.dao.DeleteMany(orm.Context(), q.Query{Keywords: q.KeyWords{"uuid": "uuid"}})
|
||||
require.NoError(suite.T(), err)
|
||||
_, err = suite.dao.DeleteMany(orm.Context(), q.Query{Keywords: q.KeyWords{"uuid": "uuid3"}})
|
||||
require.NoError(suite.T(), err)
|
||||
}
|
||||
|
||||
// TestReportList tests list reports with query parameters.
|
||||
@ -95,7 +104,7 @@ func (suite *ReportTestSuite) TestReportUpdateReportData() {
|
||||
err := suite.dao.UpdateReportData(orm.Context(), "uuid", "{}")
|
||||
suite.Require().NoError(err)
|
||||
|
||||
l, err := suite.dao.List(orm.Context(), nil)
|
||||
l, err := suite.dao.List(orm.Context(), q.New(q.KeyWords{"uuid": "uuid"}))
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(1, len(l))
|
||||
suite.Equal("{}", l[0].Report)
|
||||
@ -104,6 +113,17 @@ func (suite *ReportTestSuite) TestReportUpdateReportData() {
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (suite *ReportTestSuite) TestDeleteReportBySBOMDigest() {
|
||||
l, err := suite.dao.List(orm.Context(), nil)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(2, len(l))
|
||||
err = suite.dao.DeleteByExtraAttr(orm.Context(), v1.MimeTypeSBOMReport, "sbom_digest", "sha256:abc")
|
||||
suite.Require().NoError(err)
|
||||
l2, err := suite.dao.List(orm.Context(), nil)
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(1, len(l2))
|
||||
}
|
||||
|
||||
func (suite *ReportTestSuite) create(r *Report) {
|
||||
id, err := suite.dao.Create(orm.Context(), r)
|
||||
suite.Require().NoError(err)
|
||||
|
@ -104,6 +104,8 @@ type Manager interface {
|
||||
|
||||
// Update update report information
|
||||
Update(ctx context.Context, r *scan.Report, cols ...string) error
|
||||
// DeleteByExtraAttr delete scan_report by sbom_digest
|
||||
DeleteByExtraAttr(ctx context.Context, mimeType, attrName, attrValue string) error
|
||||
}
|
||||
|
||||
// basicManager is a default implementation of report manager.
|
||||
@ -226,3 +228,7 @@ func (bm *basicManager) List(ctx context.Context, query *q.Query) ([]*scan.Repor
|
||||
func (bm *basicManager) Update(ctx context.Context, r *scan.Report, cols ...string) error {
|
||||
return bm.dao.Update(ctx, r, cols...)
|
||||
}
|
||||
|
||||
func (bm *basicManager) DeleteByExtraAttr(ctx context.Context, mimeType, attrName, attrValue string) error {
|
||||
return bm.dao.DeleteByExtraAttr(ctx, mimeType, attrName, attrValue)
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ const (
|
||||
Duration = "duration"
|
||||
// ScanStatus ...
|
||||
ScanStatus = "scan_status"
|
||||
// ReportID ...
|
||||
ReportID = "report_id"
|
||||
// Scanner ...
|
||||
Scanner = "scanner"
|
||||
)
|
||||
|
||||
// Summary includes the sbom summary information
|
||||
|
@ -87,7 +87,7 @@ func (v *scanHandler) RequiredPermissions() []*types.Policy {
|
||||
|
||||
// PostScan defines task specific operations after the scan is complete
|
||||
func (v *scanHandler) PostScan(ctx job.Context, sr *v1.ScanRequest, _ *scanModel.Report, rawReport string, startTime time.Time, robot *model.Robot) (string, error) {
|
||||
sbomContent, err := retrieveSBOMContent(rawReport)
|
||||
sbomContent, s, err := retrieveSBOMContent(rawReport)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -107,19 +107,21 @@ func (v *scanHandler) PostScan(ctx job.Context, sr *v1.ScanRequest, _ *scanModel
|
||||
myLogger.Errorf("error when create accessory from image %v", err)
|
||||
return "", err
|
||||
}
|
||||
return v.generateReport(startTime, sr.Artifact.Repository, dgst, "Success")
|
||||
return v.generateReport(startTime, sr.Artifact.Repository, dgst, "Success", s)
|
||||
}
|
||||
|
||||
// annotations defines the annotations for the accessory artifact
|
||||
func (v *scanHandler) annotations() map[string]string {
|
||||
t := time.Now().Format(time.RFC3339)
|
||||
return map[string]string{
|
||||
"created-by": "Harbor",
|
||||
"org.opencontainers.artifact.created": time.Now().Format(time.RFC3339),
|
||||
"created": t,
|
||||
"created-by": "Harbor",
|
||||
"org.opencontainers.artifact.created": t,
|
||||
"org.opencontainers.artifact.description": "SPDX JSON SBOM",
|
||||
}
|
||||
}
|
||||
|
||||
func (v *scanHandler) generateReport(startTime time.Time, repository, digest, status string) (string, error) {
|
||||
func (v *scanHandler) generateReport(startTime time.Time, repository, digest, status string, scanner *v1.Scanner) (string, error) {
|
||||
summary := sbom.Summary{}
|
||||
endTime := time.Now()
|
||||
summary[sbom.StartTime] = startTime
|
||||
@ -128,6 +130,7 @@ func (v *scanHandler) generateReport(startTime time.Time, repository, digest, st
|
||||
summary[sbom.SBOMRepository] = repository
|
||||
summary[sbom.SBOMDigest] = digest
|
||||
summary[sbom.ScanStatus] = status
|
||||
summary[sbom.Scanner] = scanner
|
||||
rep, err := json.Marshal(summary)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -148,15 +151,15 @@ func registryFQDN(ctx context.Context) string {
|
||||
}
|
||||
|
||||
// retrieveSBOMContent retrieves the "sbom" field from the raw report
|
||||
func retrieveSBOMContent(rawReport string) ([]byte, error) {
|
||||
func retrieveSBOMContent(rawReport string) ([]byte, *v1.Scanner, error) {
|
||||
rpt := vuln.Report{}
|
||||
err := json.Unmarshal([]byte(rawReport), &rpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
sbomContent, err := json.Marshal(rpt.SBOM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return sbomContent, nil
|
||||
return sbomContent, rpt.Scanner, nil
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ export const ACTION_RESOURCE_I18N_MAP = {
|
||||
log: 'ROBOT_ACCOUNT.LOG',
|
||||
'notification-policy': 'ROBOT_ACCOUNT.NOTIFICATION_POLICY',
|
||||
quota: 'ROBOT_ACCOUNT.QUOTA',
|
||||
sbom: 'ROBOT_ACCOUNT.SBOM',
|
||||
};
|
||||
|
||||
export function convertKey(key: string) {
|
||||
|
@ -13,10 +13,13 @@
|
||||
[clrIfActive]="currentTabLinkId === 'vulnerability'">
|
||||
<clr-tab-content id="vulnerability-content">
|
||||
<hbr-artifact-vulnerabilities
|
||||
*ngIf="currentTabLinkId === 'vulnerability'"
|
||||
[artifact]="artifact"
|
||||
[projectName]="projectName"
|
||||
[projectId]="projectId"
|
||||
[repoName]="repoName"
|
||||
[scanBtnState]="getScanBtnState()"
|
||||
[hasEnabledScanner]="hasEnabledScanner()"
|
||||
[digest]="digest"
|
||||
[vulnerabilitiesLink]="
|
||||
getVulnerability()
|
||||
@ -24,16 +27,18 @@
|
||||
</clr-tab-content>
|
||||
</ng-template>
|
||||
</clr-tab>
|
||||
<clr-tab *ngIf="getSbom()">
|
||||
<clr-tab *ngIf="hasScannerSupportSBOM()">
|
||||
<button clrTabLink id="sbom" (click)="actionTab('sbom')">
|
||||
{{ 'REPOSITORY.SBOM' | translate }}
|
||||
</button>
|
||||
<ng-template [clrIfActive]="currentTabLinkId === 'sbom'">
|
||||
<clr-tab-content id="sbom-content">
|
||||
<hbr-artifact-sbom
|
||||
*ngIf="currentTabLinkId === 'sbom'"
|
||||
[artifact]="artifact"
|
||||
[projectName]="projectName"
|
||||
[projectId]="projectId"
|
||||
[hasScannerSupportSBOM]="hasScannerSupportSBOM()"
|
||||
[repoName]="repoName"
|
||||
[sbomDigest]="sbomDigest"></hbr-artifact-sbom>
|
||||
</clr-tab-content>
|
||||
@ -50,6 +55,7 @@
|
||||
[clrIfActive]="currentTabLinkId === 'build-history'">
|
||||
<clr-tab-content>
|
||||
<hbr-artifact-build-history
|
||||
*ngIf="currentTabLinkId === 'build-history'"
|
||||
[buildHistoryLink]="
|
||||
getBuildHistory()
|
||||
"></hbr-artifact-build-history>
|
||||
@ -67,6 +73,7 @@
|
||||
[clrIfActive]="currentTabLinkId === 'summary-link'">
|
||||
<clr-tab-content id="summary-content">
|
||||
<hbr-artifact-summary
|
||||
*ngIf="currentTabLinkId === 'summary-link'"
|
||||
[summaryLink]="getSummary()"></hbr-artifact-summary>
|
||||
</clr-tab-content>
|
||||
</ng-template>
|
||||
@ -81,6 +88,7 @@
|
||||
<ng-template [clrIfActive]="currentTabLinkId === 'depend-link'">
|
||||
<clr-tab-content id="depend-content">
|
||||
<hbr-artifact-dependencies
|
||||
*ngIf="currentTabLinkId === 'depend-link'"
|
||||
[dependenciesLink]="
|
||||
getDependencies()
|
||||
"></hbr-artifact-dependencies>
|
||||
@ -97,6 +105,7 @@
|
||||
<ng-template [clrIfActive]="currentTabLinkId === 'value-link'">
|
||||
<clr-tab-content id="value-content">
|
||||
<hbr-artifact-values
|
||||
*ngIf="currentTabLinkId === 'value-link'"
|
||||
[valuesLink]="getValues()"></hbr-artifact-values>
|
||||
</clr-tab-content>
|
||||
</ng-template>
|
||||
|
@ -4,6 +4,8 @@ import { AdditionLinks } from '../../../../../../../ng-swagger-gen/models/additi
|
||||
import { CURRENT_BASE_HREF } from '../../../../../shared/units/utils';
|
||||
import { SharedTestingModule } from '../../../../../shared/shared.module';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ArtifactListPageService } from '../artifact-list-page/artifact-list-page.service';
|
||||
import { ClrLoadingState } from '@clr/angular';
|
||||
|
||||
describe('ArtifactAdditionsComponent', () => {
|
||||
const mockedAdditionLinks: AdditionLinks = {
|
||||
@ -12,6 +14,18 @@ describe('ArtifactAdditionsComponent', () => {
|
||||
href: CURRENT_BASE_HREF + '/test',
|
||||
},
|
||||
};
|
||||
const mockedArtifactListPageService = {
|
||||
hasScannerSupportSBOM(): boolean {
|
||||
return true;
|
||||
},
|
||||
hasEnabledScanner(): boolean {
|
||||
return true;
|
||||
},
|
||||
getScanBtnState(): ClrLoadingState {
|
||||
return ClrLoadingState.SUCCESS;
|
||||
},
|
||||
init() {},
|
||||
};
|
||||
let component: ArtifactAdditionsComponent;
|
||||
let fixture: ComponentFixture<ArtifactAdditionsComponent>;
|
||||
|
||||
@ -20,6 +34,12 @@ describe('ArtifactAdditionsComponent', () => {
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [ArtifactAdditionsComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [
|
||||
{
|
||||
provide: ArtifactListPageService,
|
||||
useValue: mockedArtifactListPageService,
|
||||
},
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
@ -27,6 +47,7 @@ describe('ArtifactAdditionsComponent', () => {
|
||||
fixture = TestBed.createComponent(ArtifactAdditionsComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.additionLinks = mockedAdditionLinks;
|
||||
component.tab = 'vulnerability';
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
@ -10,7 +10,8 @@ import { ADDITIONS } from './models';
|
||||
import { AdditionLinks } from '../../../../../../../ng-swagger-gen/models/addition-links';
|
||||
import { AdditionLink } from '../../../../../../../ng-swagger-gen/models/addition-link';
|
||||
import { Artifact } from '../../../../../../../ng-swagger-gen/models/artifact';
|
||||
import { ClrTabs } from '@clr/angular';
|
||||
import { ClrLoadingState, ClrTabs } from '@clr/angular';
|
||||
import { ArtifactListPageService } from '../artifact-list-page/artifact-list-page.service';
|
||||
|
||||
@Component({
|
||||
selector: 'artifact-additions',
|
||||
@ -32,14 +33,21 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
|
||||
@Input()
|
||||
tab: string;
|
||||
|
||||
@Input() currentTabLinkId: string = 'vulnerability';
|
||||
@Input() currentTabLinkId: string = '';
|
||||
activeTab: string = null;
|
||||
|
||||
@ViewChild('additionsTab') tabs: ClrTabs;
|
||||
constructor(private ref: ChangeDetectorRef) {}
|
||||
constructor(
|
||||
private ref: ChangeDetectorRef,
|
||||
private artifactListPageService: ArtifactListPageService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.activeTab = this.tab;
|
||||
if (!this.activeTab) {
|
||||
this.currentTabLinkId = 'vulnerability';
|
||||
}
|
||||
this.artifactListPageService.init(this.projectId);
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
@ -50,6 +58,10 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
|
||||
this.ref.detectChanges();
|
||||
}
|
||||
|
||||
hasScannerSupportSBOM(): boolean {
|
||||
return this.artifactListPageService.hasScannerSupportSBOM();
|
||||
}
|
||||
|
||||
getVulnerability(): AdditionLink {
|
||||
if (
|
||||
this.additionLinks &&
|
||||
@ -59,12 +71,7 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getSbom(): AdditionLink {
|
||||
if (this.additionLinks && this.additionLinks[ADDITIONS.SBOMS]) {
|
||||
return this.additionLinks[ADDITIONS.SBOMS];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
getBuildHistory(): AdditionLink {
|
||||
if (this.additionLinks && this.additionLinks[ADDITIONS.BUILD_HISTORY]) {
|
||||
return this.additionLinks[ADDITIONS.BUILD_HISTORY];
|
||||
@ -93,4 +100,12 @@ export class ArtifactAdditionsComponent implements AfterViewChecked, OnInit {
|
||||
actionTab(tab: string): void {
|
||||
this.currentTabLinkId = tab;
|
||||
}
|
||||
|
||||
getScanBtnState(): ClrLoadingState {
|
||||
return this.artifactListPageService.getScanBtnState();
|
||||
}
|
||||
|
||||
hasEnabledScanner(): boolean {
|
||||
return this.artifactListPageService.hasEnabledScanner();
|
||||
}
|
||||
}
|
||||
|
@ -32,12 +32,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</clr-dg-action-bar>
|
||||
<clr-dg-column [clrDgField]="'package'" class="package-medium">{{
|
||||
'SBOM.GRID.COLUMN_PACKAGE' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgField]="'version'" class="version-medium">{{
|
||||
'SBOM.GRID.COLUMN_VERSION' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column
|
||||
[clrDgSortBy]="'name'"
|
||||
[clrDgField]="'name'"
|
||||
class="package-medium"
|
||||
>{{ 'SBOM.GRID.COLUMN_PACKAGE' | translate }}</clr-dg-column
|
||||
>
|
||||
<clr-dg-column
|
||||
[clrDgSortBy]="'versionInfo'"
|
||||
[clrDgField]="'versionInfo'"
|
||||
class="version-medium"
|
||||
>{{ 'SBOM.GRID.COLUMN_VERSION' | translate }}</clr-dg-column
|
||||
>
|
||||
<clr-dg-column>{{
|
||||
'SBOM.GRID.COLUMN_LICENSE' | translate
|
||||
}}</clr-dg-column>
|
||||
|
@ -10,7 +10,6 @@ import {
|
||||
} from '@ngx-translate/core';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { UserPermissionService } from '../../../../../../shared/services';
|
||||
import { AdditionLink } from '../../../../../../../../ng-swagger-gen/models/addition-link';
|
||||
import { ErrorHandler } from '../../../../../../shared/units/error-handler';
|
||||
import { SessionService } from '../../../../../../shared/services/session.service';
|
||||
import { SessionUser } from '../../../../../../shared/entities/session-user';
|
||||
|
@ -1,13 +1,6 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ClrDatagridStateInterface, ClrLoadingState } from '@clr/angular';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { AdditionLink } from '../../../../../../../../ng-swagger-gen/models/addition-link';
|
||||
import {
|
||||
ScannerVo,
|
||||
UserPermissionService,
|
||||
@ -30,7 +23,6 @@ import {
|
||||
HarborEvent,
|
||||
} from '../../../../../../services/event-service/event.service';
|
||||
import { severityText } from '../../../../../left-side-nav/interrogation-services/vulnerability-database/security-hub.interface';
|
||||
import { AppConfigService } from 'src/app/services/app-config.service';
|
||||
|
||||
import {
|
||||
ArtifactSbom,
|
||||
@ -38,8 +30,7 @@ import {
|
||||
getArtifactSbom,
|
||||
} from '../../artifact';
|
||||
import { ArtifactService } from 'ng-swagger-gen/services';
|
||||
import { ScanTypes } from 'src/app/shared/entities/shared.const';
|
||||
import { ArtifactListPageService } from '../../artifact-list-page/artifact-list-page.service';
|
||||
import { ScanTypes } from '../../../../../../shared/entities/shared.const';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-artifact-sbom',
|
||||
@ -56,13 +47,12 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
sbomDigest: string;
|
||||
@Input() artifact: Artifact;
|
||||
@Input() hasScannerSupportSBOM: boolean = false;
|
||||
|
||||
artifactSbom: ArtifactSbom;
|
||||
loading: boolean = false;
|
||||
hasScannerSupportSBOM: boolean = false;
|
||||
downloadSbomBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
|
||||
hasSbomPermission: boolean = false;
|
||||
|
||||
hasShowLoading: boolean = false;
|
||||
sub: Subscription;
|
||||
hasViewInitWithDelay: boolean = false;
|
||||
@ -73,16 +63,13 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
|
||||
readonly severityText = severityText;
|
||||
constructor(
|
||||
private errorHandler: ErrorHandler,
|
||||
private appConfigService: AppConfigService,
|
||||
private artifactService: ArtifactService,
|
||||
private artifactListPageService: ArtifactListPageService,
|
||||
private userPermissionService: UserPermissionService,
|
||||
private eventService: EventService,
|
||||
private session: SessionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.artifactListPageService.init(this.projectId);
|
||||
this.getSbom();
|
||||
this.getSbomPermission();
|
||||
if (!this.sub) {
|
||||
@ -222,8 +209,6 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
canDownloadSbom(): boolean {
|
||||
this.hasScannerSupportSBOM =
|
||||
this.artifactListPageService.hasScannerSupportSBOM();
|
||||
return (
|
||||
this.hasScannerSupportSBOM &&
|
||||
//this.hasSbomPermission &&
|
||||
@ -234,7 +219,12 @@ export class ArtifactSbomComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
artifactSbomPackages(): ArtifactSbomPackageItem[] {
|
||||
return this.artifactSbom?.sbomPackage?.packages ?? [];
|
||||
return (
|
||||
this.artifactSbom?.sbomPackage?.packages?.filter(
|
||||
item =>
|
||||
item?.name || item?.versionInfo || item?.licenseConcluded
|
||||
) ?? []
|
||||
);
|
||||
}
|
||||
|
||||
load(state: ClrDatagridStateInterface) {
|
||||
|
@ -50,14 +50,13 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
digest: string;
|
||||
@Input() artifact: Artifact;
|
||||
@Input() scanBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
|
||||
@Input() hasEnabledScanner: boolean = false;
|
||||
scan_overview: any;
|
||||
scanner: ScannerVo;
|
||||
projectScanner: ScannerVo;
|
||||
|
||||
scanningResults: VulnerabilityItem[] = [];
|
||||
loading: boolean = false;
|
||||
hasEnabledScanner: boolean = false;
|
||||
scanBtnState: ClrLoadingState = ClrLoadingState.DEFAULT;
|
||||
severitySort: ClrDatagridComparatorInterface<VulnerabilityItem>;
|
||||
cvssSort: ClrDatagridComparatorInterface<VulnerabilityItem>;
|
||||
hasScanningPermission: boolean = false;
|
||||
@ -112,7 +111,6 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
this.getVulnerabilities();
|
||||
this.getScanningPermission();
|
||||
this.getProjectScanner();
|
||||
if (!this.sub) {
|
||||
this.sub = this.eventService.subscribe(
|
||||
HarborEvent.UPDATE_VULNERABILITY_INFO,
|
||||
@ -203,30 +201,6 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
getProjectScanner(): void {
|
||||
this.hasEnabledScanner = false;
|
||||
this.scanBtnState = ClrLoadingState.LOADING;
|
||||
this.scanningService.getProjectScanner(this.projectId).subscribe(
|
||||
response => {
|
||||
if (
|
||||
response &&
|
||||
'{}' !== JSON.stringify(response) &&
|
||||
!response.disabled &&
|
||||
response.health === 'healthy'
|
||||
) {
|
||||
this.scanBtnState = ClrLoadingState.SUCCESS;
|
||||
this.hasEnabledScanner = true;
|
||||
} else {
|
||||
this.scanBtnState = ClrLoadingState.ERROR;
|
||||
}
|
||||
this.projectScanner = response;
|
||||
},
|
||||
error => {
|
||||
this.scanBtnState = ClrLoadingState.ERROR;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getLevel(v: VulnerabilityItem): number {
|
||||
if (v && v.severity && SEVERITY_LEVEL_MAP[v.severity]) {
|
||||
return SEVERITY_LEVEL_MAP[v.severity];
|
||||
|
@ -65,10 +65,6 @@
|
||||
class="action-dropdown"
|
||||
clrPosition="bottom-left"
|
||||
*clrIfOpen>
|
||||
<div
|
||||
class="dropdown-divider"
|
||||
role="separator"
|
||||
aria-hidden="true"></div>
|
||||
<button
|
||||
clrDropdownItem
|
||||
id="stop-scan"
|
||||
|
@ -984,6 +984,14 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
if (this.selectedRow && this.selectedRow.length) {
|
||||
for (let i = 0; i < this.selectedRow.length; i++) {
|
||||
if (artifact.digest === this.selectedRow[i].digest) {
|
||||
if (artifact.sbom_overview) {
|
||||
this.selectedRow[i].sbom_overview =
|
||||
artifact.sbom_overview;
|
||||
}
|
||||
if (artifact.sbom_overview.sbom_digest) {
|
||||
this.selectedRow[i].sbomDigest =
|
||||
artifact.sbom_overview.sbom_digest;
|
||||
}
|
||||
this.selectedRow.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
@ -1099,7 +1107,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
||||
res?.filter(
|
||||
item =>
|
||||
item.type === AccessoryType.SBOM
|
||||
)?.[0]?.digest ?? null;
|
||||
)?.[0]?.digest ?? undefined;
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
|
@ -76,7 +76,7 @@ export enum AccessoryType {
|
||||
COSIGN = 'signature.cosign',
|
||||
NOTATION = 'signature.notation',
|
||||
NYDUS = 'accelerator.nydus',
|
||||
SBOM = 'harbor.sbom',
|
||||
SBOM = 'sbom.harbor',
|
||||
}
|
||||
|
||||
export enum ArtifactType {
|
||||
|
@ -68,9 +68,7 @@ export class SbomTipHistogramComponent {
|
||||
}
|
||||
|
||||
get noSbom(): boolean {
|
||||
return (
|
||||
this.sbomSummary.scan_status === SBOM_SCAN_STATUS.NOT_GENERATED_SBOM
|
||||
);
|
||||
return this.sbomDigest === undefined || this.sbomDigest === '';
|
||||
}
|
||||
|
||||
isThemeLight() {
|
||||
|
@ -2,6 +2,12 @@
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
hbr-sbom-bar {
|
||||
.label,.not-scan {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.bar-state {
|
||||
.unknow-text {
|
||||
margin-left: -5px;
|
||||
@ -15,6 +21,7 @@
|
||||
.bar-state-chart {
|
||||
.loop-height {
|
||||
height: 2px;
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,144 +36,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scanning-button {
|
||||
height: 24px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
top: -12px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tip-wrapper {
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
|
||||
.bar-tooltip-font-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bar-summary {
|
||||
margin-top: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.bar-scanning-time {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.bar-summary-item {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.bar-summary-item span:nth-child(1){
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.bar-summary-item span:nth-child(2){
|
||||
width: 28px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.option-right {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.refresh-btn:hover {
|
||||
color: #007CBB;
|
||||
}
|
||||
|
||||
.tip-icon-medium {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.tip-icon-low {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.font-color-green{
|
||||
color:green;
|
||||
}
|
||||
/* stylelint-disable */
|
||||
.bar-tooltip-font-larger span{
|
||||
font-size:16px;
|
||||
vertical-align:middle
|
||||
}
|
||||
|
||||
hr{
|
||||
border-bottom: 0;
|
||||
border-color: #aaa;
|
||||
margin: 6px -10px;
|
||||
}
|
||||
|
||||
.font-weight-600{
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.rightPos{
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
right: 35px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.help-icon {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.mt-3px {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.label-critical {
|
||||
background:#ff4d2e;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.label-danger {
|
||||
background:#ff8f3d!important;
|
||||
color:#000!important;
|
||||
}
|
||||
|
||||
.label-medium {
|
||||
background-color: #ffce66;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.label-low {
|
||||
background: #fff1ad;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.label-none {
|
||||
background-color: #2ec0ff;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
border: none;
|
||||
}
|
||||
|
||||
hbr-vulnerability-bar {
|
||||
.label,.not-scan {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.stopped {
|
||||
border-color: #cccc15;
|
||||
}
|
||||
|
@ -142,7 +142,16 @@ export const errorHandler = function (error: any): string {
|
||||
}
|
||||
// Not a standard error return Basically not used cover unknown error
|
||||
try {
|
||||
return JSON.parse(error.error).message;
|
||||
const jsonError = JSON.parse(error.error);
|
||||
if (jsonError.errors && jsonError.errors instanceof Array) {
|
||||
return (
|
||||
jsonError.errors?.map(error => error.message) ?? [
|
||||
'UNKNOWN_ERROR',
|
||||
]
|
||||
).join(',');
|
||||
} else {
|
||||
return JSON.parse(error.error).message;
|
||||
}
|
||||
} catch (err) {}
|
||||
// Not a standard error return Basically not used cover unknown error
|
||||
if (typeof error.error === 'string') {
|
||||
|
@ -406,6 +406,7 @@
|
||||
"REPOSITORY": "Repository",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessory",
|
||||
"ARTIFACT_ADDITION": "Artifact Addition",
|
||||
@ -1061,7 +1062,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -406,6 +406,7 @@
|
||||
"REPOSITORY": "Repository",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessory",
|
||||
"ARTIFACT_ADDITION": "Artifact Addition",
|
||||
@ -1062,7 +1063,7 @@
|
||||
"GENERATE": "Generate SBOM ",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -407,6 +407,7 @@
|
||||
"REPOSITORY": "Repository",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessory",
|
||||
"ARTIFACT_ADDITION": "Artifact Addition",
|
||||
@ -1060,7 +1061,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -406,6 +406,7 @@
|
||||
"REPOSITORY": "Dépôt",
|
||||
"ARTIFACT": "Artefact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessoire",
|
||||
"ARTIFACT_ADDITION": "Artefact Addition",
|
||||
@ -1060,7 +1061,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -403,6 +403,7 @@
|
||||
"REPOSITORY": "저장소",
|
||||
"ARTIFACT": "아티팩트",
|
||||
"SCAN": "스캔",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "태그",
|
||||
"ACCESSORY": "액세서리",
|
||||
"ARTIFACT_ADDITION": "아티팩트 추가",
|
||||
@ -1059,7 +1060,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -404,6 +404,7 @@
|
||||
"REPOSITORY": "Repository",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessory",
|
||||
"ARTIFACT_ADDITION": "Artifact Addition",
|
||||
@ -1058,7 +1059,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -406,6 +406,7 @@
|
||||
"REPOSITORY": "Repository",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessory",
|
||||
"ARTIFACT_ADDITION": "Artifact Addition",
|
||||
@ -1061,7 +1062,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -405,6 +405,7 @@
|
||||
"REPOSITORY": "仓库",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "扫描",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "附件",
|
||||
"ARTIFACT_ADDITION": "Artifact 额外信息",
|
||||
@ -1059,7 +1060,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -405,6 +405,7 @@
|
||||
"REPOSITORY": "Repository",
|
||||
"ARTIFACT": "Artifact",
|
||||
"SCAN": "Scan",
|
||||
"SBOM": "SBOM",
|
||||
"TAG": "Tag",
|
||||
"ACCESSORY": "Accessory",
|
||||
"ARTIFACT_ADDITION": "Artifact Addition",
|
||||
@ -1058,7 +1059,7 @@
|
||||
"GENERATE": "Generate SBOM",
|
||||
"DOWNLOAD": "Download SBOM",
|
||||
"Details": "SBOM details",
|
||||
"STOP": "Stop SBOM",
|
||||
"STOP": "Stop Generate SBOM",
|
||||
"TRIGGER_STOP_SUCCESS": "Trigger stopping SBOM generation successfully"
|
||||
},
|
||||
"VULNERABILITY": {
|
||||
|
@ -21,16 +21,12 @@ import (
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
||||
sbomModel "github.com/goharbor/harbor/src/pkg/scan/sbom/model"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/handler/model"
|
||||
)
|
||||
|
||||
const (
|
||||
vulnerabilitiesAddition = "vulnerabilities"
|
||||
startTime = "start_time"
|
||||
endTime = "end_time"
|
||||
scanStatus = "scan_status"
|
||||
sbomDigest = "sbom_digest"
|
||||
duration = "duration"
|
||||
)
|
||||
|
||||
// NewScanReportAssembler returns vul assembler
|
||||
@ -92,17 +88,19 @@ func (assembler *ScanReportAssembler) Assemble(ctx context.Context) error {
|
||||
overview, err := assembler.scanCtl.GetSummary(ctx, &artifact.Artifact, []string{v1.MimeTypeSBOMReport})
|
||||
if err != nil {
|
||||
log.Warningf("get scan summary of artifact %s@%s for %s failed, error:%v", artifact.RepositoryName, artifact.Digest, v1.MimeTypeSBOMReport, err)
|
||||
} else if len(overview) > 0 {
|
||||
}
|
||||
if len(overview) > 0 {
|
||||
artifact.SBOMOverView = map[string]interface{}{
|
||||
startTime: overview[startTime],
|
||||
endTime: overview[endTime],
|
||||
scanStatus: overview[scanStatus],
|
||||
sbomDigest: overview[sbomDigest],
|
||||
duration: overview[duration],
|
||||
sbomModel.StartTime: overview[sbomModel.StartTime],
|
||||
sbomModel.EndTime: overview[sbomModel.EndTime],
|
||||
sbomModel.ScanStatus: overview[sbomModel.ScanStatus],
|
||||
sbomModel.SBOMDigest: overview[sbomModel.SBOMDigest],
|
||||
sbomModel.Duration: overview[sbomModel.Duration],
|
||||
sbomModel.ReportID: overview[sbomModel.ReportID],
|
||||
sbomModel.Scanner: overview[sbomModel.Scanner],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -87,6 +87,24 @@ func (_m *Manager) DeleteByDigests(ctx context.Context, digests ...string) error
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteByExtraAttr provides a mock function with given fields: ctx, mimeType, attrName, attrValue
|
||||
func (_m *Manager) DeleteByExtraAttr(ctx context.Context, mimeType string, attrName string, attrValue string) error {
|
||||
ret := _m.Called(ctx, mimeType, attrName, attrValue)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteByExtraAttr")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok {
|
||||
r0 = rf(ctx, mimeType, attrName, attrValue)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetBy provides a mock function with given fields: ctx, digest, registrationUUID, mimeTypes
|
||||
func (_m *Manager) GetBy(ctx context.Context, digest string, registrationUUID string, mimeTypes []string) ([]*scan.Report, error) {
|
||||
ret := _m.Called(ctx, digest, registrationUUID, mimeTypes)
|
||||
|
@ -89,8 +89,11 @@ copy_artifact = Permission("{}/projects/{}/repositories/target_repo/artifacts?fr
|
||||
delete_artifact = Permission("{}/projects/{}/repositories/target_repo/artifacts/{}".format(harbor_base_url, project_name, source_artifact_tag), "DELETE", 200)
|
||||
|
||||
# 6. Resource scan actions: ['read', 'create', 'stop']
|
||||
stop_scan_payload = {
|
||||
"scan_type": "vulnerability"
|
||||
}
|
||||
create_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202)
|
||||
stop_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202)
|
||||
stop_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/stop".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "POST", 202, stop_scan_payload)
|
||||
read_scan = Permission("{}/projects/{}/repositories/{}/artifacts/{}/scan/83be44fd-1234-5678-b49f-4b6d6e8f5730/log".format(harbor_base_url, project_name, source_artifact_name, source_artifact_tag), "get", 404)
|
||||
|
||||
# 7. Resource tag actions: ['list', 'create', 'delete']
|
||||
|
@ -37,6 +37,7 @@ Scan Artifact
|
||||
Retry Element Click ${scan_artifact_btn}
|
||||
|
||||
Stop Scan Artifact
|
||||
Retry Element Click ${artifact_action_xpath}
|
||||
Retry Element Click ${stop_scan_artifact_btn}
|
||||
|
||||
Check Scan Artifact Job Status Is Stopped
|
||||
|
@ -24,8 +24,8 @@ Create A Project Robot Account
|
||||
${permission_count}= Create Dictionary
|
||||
${total}= Set Variable 0
|
||||
IF '${first_resource}' == 'all'
|
||||
Set To Dictionary ${permission_count} all=56
|
||||
${total}= Set Variable 56
|
||||
Set To Dictionary ${permission_count} all=59
|
||||
${total}= Set Variable 59
|
||||
Retry Element Click //span[text()='Select all']
|
||||
ELSE
|
||||
FOR ${item} IN @{resources}
|
||||
|
@ -51,3 +51,4 @@ ${scanner_password_input} //*[@id='scanner-password']
|
||||
${scanner_token_input} //*[@id='scanner-token']
|
||||
${scanner_apikey_input} //*[@id='scanner-apiKey']
|
||||
${scanner_set_default_btn} //*[@id='set-default']
|
||||
${scanner_list_refresh_btn} //span[@class='refresh-btn']//clr-icon[@role='none']
|
||||
|
@ -76,6 +76,7 @@ Resource Harbor-Pages/Job_Service_Dashboard_Elements.robot
|
||||
Resource Harbor-Pages/SecurityHub.robot
|
||||
Resource Harbor-Pages/SecurityHub_Elements.robot
|
||||
Resource Harbor-Pages/Verify.robot
|
||||
Resource Harbor-Pages/Vulnerability_Elements.robot
|
||||
Resource Docker-Util.robot
|
||||
Resource CNAB_Util.robot
|
||||
Resource Helm-Util.robot
|
||||
|
@ -745,7 +745,7 @@ Test Case - System Robot Account
|
||||
|
||||
${robot_account_name} ${token}= Create A System Robot Account sys2${d} days days=2 description=For testing cover_all_project_resources=${true}
|
||||
Push image ${ip} '${robot_account_name}' ${token} project${d} hello-world:latest
|
||||
Retry Wait Element Visible //clr-dg-row[.//clr-dg-cell[contains(.,'${robot_account_name}')] and .//clr-icon[contains(@class, 'color-green')] and .//span[text()='All projects with'] and .//button[text()=' 56 PERMISSION(S) '] and .//span[contains(.,'1d 23h')] and .//clr-dg-cell[text()='For testing'] and .//clr-dg-cell//span[text()=' None ']]
|
||||
Retry Wait Element Visible //clr-dg-row[.//clr-dg-cell[contains(.,'${robot_account_name}')] and .//clr-icon[contains(@class, 'color-green')] and .//span[text()='All projects with'] and .//button[text()=' 59 PERMISSION(S) '] and .//span[contains(.,'1d 23h')] and .//clr-dg-cell[text()='For testing'] and .//clr-dg-cell//span[text()=' None ']]
|
||||
Retry Action Keyword Check System Robot Account API Permission ${robot_account_name} ${token} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} all 1
|
||||
Retry Action Keyword Check Project Robot Account API Permission ${robot_account_name} ${token} ${HARBOR_ADMIN} ${HARBOR_PASSWORD} ${project_id} ${project_name} hello-world latest all
|
||||
Close Browser
|
||||
@ -885,13 +885,13 @@ Test Case - Audit Log And Purge
|
||||
# pull artifact
|
||||
Docker Pull ${ip}/project${d}/${image}:${tag1}
|
||||
Docker Logout ${ip}
|
||||
Verify Log ${user} project${d}/${image}:${sha256} artifact pull
|
||||
Verify Log ${user} project${d}/${image}@${sha256} artifact pull
|
||||
Go Into Repo project${d} ${image}
|
||||
# delete artifact
|
||||
@{tag_list} Create List ${tag1}
|
||||
Multi-delete Artifact @{tag_list}
|
||||
Switch To Logs
|
||||
Verify Log ${user} project${d}/${image}:${sha256} artifact delete
|
||||
Verify Log ${user} project${d}/${image}@${sha256} artifact delete
|
||||
Go Into Project project${d}
|
||||
# delete repository
|
||||
Delete Repo project${d} ${image}
|
||||
@ -1151,8 +1151,8 @@ Test Case - Retain Image Last Pull Time
|
||||
Scan Repo ${tag} Succeed
|
||||
Sleep 15
|
||||
Reload Page
|
||||
Retry Wait Element Visible //clr-dg-row//clr-dg-cell[9]
|
||||
${last_pull_time}= Get Text //clr-dg-row//clr-dg-cell[9]
|
||||
Retry Wait Element Visible //clr-dg-row//clr-dg-cell[10]
|
||||
${last_pull_time}= Get Text //clr-dg-row//clr-dg-cell[10]
|
||||
Should Be Empty ${last_pull_time}
|
||||
Switch To Configuration System Setting
|
||||
Set Up Retain Image Last Pull Time disable
|
||||
@ -1160,8 +1160,8 @@ Test Case - Retain Image Last Pull Time
|
||||
Scan Repo ${tag} Succeed
|
||||
Sleep 15
|
||||
Reload Page
|
||||
Retry Wait Element Visible //clr-dg-row//clr-dg-cell[9]
|
||||
${last_pull_time}= Get Text //clr-dg-row//clr-dg-cell[9]
|
||||
Retry Wait Element Visible //clr-dg-row//clr-dg-cell[10]
|
||||
${last_pull_time}= Get Text //clr-dg-row//clr-dg-cell[10]
|
||||
Should Not Be Empty ${last_pull_time}
|
||||
Close Browser
|
||||
|
||||
|
@ -182,7 +182,7 @@ Test Case - External Scanner CRUD
|
||||
Filter Scanner By Name scanner${d}
|
||||
Filter Scanner By Endpoint ${SCANNER_ENDPOINT}
|
||||
Retry Wait Element Count //clr-dg-row 1
|
||||
Retry Wait Until Page Contains Element //clr-dg-row[.//span[text()='scanner${d}'] and .//clr-dg-cell[text()='${SCANNER_ENDPOINT}'] and .//span[text()='Healthy'] and .//clr-dg-cell[text()='None']]
|
||||
Retry Double Keywords When Error Retry Element Click xpath=${scanner_list_refresh_btn} Retry Wait Until Page Contains Element //clr-dg-row[.//span[text()='scanner${d}'] and .//clr-dg-cell[text()='${SCANNER_ENDPOINT}'] and .//span[text()='Healthy'] and .//clr-dg-cell[text()='None']]
|
||||
# Delete this scanner
|
||||
Delete Scanner scanner${d}
|
||||
Close Browser
|
||||
|
Loading…
Reference in New Issue
Block a user