harbor/src/pkg/scan/dao/scanner/model.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
}