mirror of https://github.com/goharbor/harbor.git
208 lines
6.1 KiB
Go
208 lines
6.1 KiB
Go
// 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 scanner
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/goharbor/harbor/src/lib"
|
|
"github.com/goharbor/harbor/src/lib/errors"
|
|
"github.com/goharbor/harbor/src/pkg/scan/rest/auth"
|
|
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
|
|
)
|
|
|
|
const (
|
|
authorizationType = "harbor.scanner-adapter/registry-authorization-type"
|
|
authorizationBearer = "Bearer"
|
|
authorizationBasic = "Basic"
|
|
)
|
|
|
|
// Registration represents a named configuration for invoking a scanner via its adapter.
|
|
// UUID will be used to track the scanner.Endpoint as unique ID
|
|
type Registration struct {
|
|
// Basic information
|
|
// int64 ID is kept for being aligned with previous DB schema
|
|
ID int64 `orm:"pk;auto;column(id)" json:"-"`
|
|
UUID string `orm:"unique;column(uuid)" json:"uuid"`
|
|
Name string `orm:"unique;column(name);size(128)" json:"name"`
|
|
Description string `orm:"column(description);null;size(1024)" json:"description"`
|
|
URL string `orm:"column(url);unique;size(512)" json:"url"`
|
|
Disabled bool `orm:"column(disabled);default(true)" json:"disabled"`
|
|
IsDefault bool `orm:"column(is_default);default(false)" json:"is_default"`
|
|
Health string `orm:"-" json:"health,omitempty"`
|
|
|
|
// Authentication settings
|
|
// "","Basic", "Bearer" and api key header "X-ScannerAdapter-API-Key" can be supported
|
|
Auth string `orm:"column(auth);size(16)" json:"auth"`
|
|
AccessCredential string `orm:"column(access_cred);null;size(512)" json:"access_credential,omitempty"`
|
|
|
|
// Http connection settings
|
|
SkipCertVerify bool `orm:"column(skip_cert_verify);default(false)" json:"skip_certVerify"`
|
|
|
|
// Indicate whether use internal registry addr for the scanner to pull content
|
|
UseInternalAddr bool `orm:"column(use_internal_addr);default(false)" json:"use_internal_addr"`
|
|
|
|
// Indicate if the registration is immutable which is not allowed to remove
|
|
Immutable bool `orm:"column(immutable);default(false)" json:"-"`
|
|
|
|
// Optional properties for describing the adapter
|
|
Adapter string `orm:"-" json:"adapter,omitempty"`
|
|
Vendor string `orm:"-" json:"vendor,omitempty"`
|
|
Version string `orm:"-" json:"version,omitempty"`
|
|
|
|
Metadata *v1.ScannerAdapterMetadata `orm:"-" json:"-"`
|
|
|
|
// Timestamps
|
|
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
|
|
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
|
|
Capabilities map[string]interface{} `orm:"-" json:"capabilities,omitempty"`
|
|
}
|
|
|
|
// TableName for Endpoint
|
|
func (r *Registration) TableName() string {
|
|
return "scanner_registration"
|
|
}
|
|
|
|
// FromJSON parses registration from json data
|
|
func (r *Registration) FromJSON(jsonData string) error {
|
|
if len(jsonData) == 0 {
|
|
return errors.New("empty json data to parse")
|
|
}
|
|
|
|
return json.Unmarshal([]byte(jsonData), r)
|
|
}
|
|
|
|
// ToJSON marshals registration to JSON data
|
|
func (r *Registration) ToJSON() (string, error) {
|
|
data, err := json.Marshal(r)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(data), nil
|
|
}
|
|
|
|
// Validate registration
|
|
func (r *Registration) Validate(checkUUID bool) error {
|
|
if checkUUID && len(r.UUID) == 0 {
|
|
return errors.New("malformed endpoint")
|
|
}
|
|
|
|
if len(r.Name) == 0 {
|
|
return errors.New("missing registration name")
|
|
}
|
|
|
|
url, err := lib.ValidateHTTPURL(r.URL)
|
|
if err != nil {
|
|
return errors.Wrap(err, "scanner registration validate")
|
|
}
|
|
r.URL = url
|
|
|
|
if len(r.Auth) > 0 &&
|
|
r.Auth != auth.Basic &&
|
|
r.Auth != auth.Bearer &&
|
|
r.Auth != auth.APIKey {
|
|
return errors.Errorf("auth type %s is not supported", r.Auth)
|
|
}
|
|
|
|
if len(r.Auth) > 0 && len(r.AccessCredential) == 0 {
|
|
return errors.Errorf("access_credential is required for auth type %s", r.Auth)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Client returns client of registration
|
|
func (r *Registration) Client(pool v1.ClientPool) (v1.Client, error) {
|
|
if err := r.Validate(false); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pool.Get(r.URL, r.Auth, r.AccessCredential, r.SkipCertVerify)
|
|
}
|
|
|
|
// HasCapability returns true when mime type of the artifact support by the scanner
|
|
func (r *Registration) HasCapability(manifestMimeType string) bool {
|
|
if r.Metadata == nil {
|
|
return false
|
|
}
|
|
|
|
for _, capability := range r.Metadata.Capabilities {
|
|
for _, mt := range capability.ConsumesMimeTypes {
|
|
if mt == manifestMimeType {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// GetProducesMimeTypes returns produces mime types for the artifact
|
|
func (r *Registration) GetProducesMimeTypes(mimeType string, scanType string) []string {
|
|
if r.Metadata == nil {
|
|
return nil
|
|
}
|
|
for _, capability := range r.Metadata.Capabilities {
|
|
capType := capability.Type
|
|
if len(capType) == 0 {
|
|
capType = v1.ScanTypeVulnerability
|
|
}
|
|
if scanType == capType {
|
|
for _, mt := range capability.ConsumesMimeTypes {
|
|
if mt == mimeType {
|
|
return capability.ProducesMimeTypes
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetCapability returns capability for the mime type
|
|
func (r *Registration) GetCapability(mimeType string) *v1.ScannerCapability {
|
|
if r.Metadata == nil {
|
|
return nil
|
|
}
|
|
|
|
for _, capability := range r.Metadata.Capabilities {
|
|
for _, mt := range capability.ConsumesMimeTypes {
|
|
if mt == mimeType {
|
|
return capability
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetRegistryAuthorizationType returns the registry authorization type of the scanner
|
|
func (r *Registration) GetRegistryAuthorizationType() string {
|
|
var auth string
|
|
if r.Metadata != nil && r.Metadata.Properties != nil {
|
|
if v, ok := r.Metadata.Properties[authorizationType]; ok {
|
|
auth = v
|
|
}
|
|
}
|
|
|
|
if auth != authorizationBasic && auth != authorizationBearer {
|
|
auth = authorizationBasic
|
|
}
|
|
|
|
return auth
|
|
}
|